gameux: Loading of game statistics implemented.
[wine] / dlls / ole32 / rpc.c
1 /*
2  *      RPC Manager
3  *
4  * Copyright 2001  Ove Kåven, TransGaming Technologies
5  * Copyright 2002  Marcus Meissner
6  * Copyright 2005  Mike Hearn, Rob Shearman for CodeWeavers
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <stdarg.h>
27 #include <string.h>
28
29 #define COBJMACROS
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winuser.h"
36 #include "winsvc.h"
37 #include "objbase.h"
38 #include "ole2.h"
39 #include "rpc.h"
40 #include "winerror.h"
41 #include "winreg.h"
42 #include "wine/unicode.h"
43
44 #include "compobj_private.h"
45
46 #include "wine/debug.h"
47
48 WINE_DEFAULT_DEBUG_CHANNEL(ole);
49
50 static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg);
51
52 /* we only use one function to dispatch calls for all methods - we use the
53  * RPC_IF_OLE flag to tell the RPC runtime that this is the case */
54 static RPC_DISPATCH_FUNCTION rpc_dispatch_table[1] = { dispatch_rpc }; /* (RO) */
55 static RPC_DISPATCH_TABLE rpc_dispatch = { 1, rpc_dispatch_table }; /* (RO) */
56
57 static struct list registered_interfaces = LIST_INIT(registered_interfaces); /* (CS csRegIf) */
58 static CRITICAL_SECTION csRegIf;
59 static CRITICAL_SECTION_DEBUG csRegIf_debug =
60 {
61     0, 0, &csRegIf,
62     { &csRegIf_debug.ProcessLocksList, &csRegIf_debug.ProcessLocksList },
63       0, 0, { (DWORD_PTR)(__FILE__ ": dcom registered server interfaces") }
64 };
65 static CRITICAL_SECTION csRegIf = { &csRegIf_debug, -1, 0, 0, 0, 0 };
66
67 static struct list channel_hooks = LIST_INIT(channel_hooks); /* (CS csChannelHook) */
68 static CRITICAL_SECTION csChannelHook;
69 static CRITICAL_SECTION_DEBUG csChannelHook_debug =
70 {
71     0, 0, &csChannelHook,
72     { &csChannelHook_debug.ProcessLocksList, &csChannelHook_debug.ProcessLocksList },
73       0, 0, { (DWORD_PTR)(__FILE__ ": channel hooks") }
74 };
75 static CRITICAL_SECTION csChannelHook = { &csChannelHook_debug, -1, 0, 0, 0, 0 };
76
77 static WCHAR wszRpcTransport[] = {'n','c','a','l','r','p','c',0};
78
79
80 struct registered_if
81 {
82     struct list entry;
83     DWORD refs; /* ref count */
84     RPC_SERVER_INTERFACE If; /* interface registered with the RPC runtime */
85 };
86
87 /* get the pipe endpoint specified of the specified apartment */
88 static inline void get_rpc_endpoint(LPWSTR endpoint, const OXID *oxid)
89 {
90     /* FIXME: should get endpoint from rpcss */
91     static const WCHAR wszEndpointFormat[] = {'\\','p','i','p','e','\\','O','L','E','_','%','0','8','l','x','%','0','8','l','x',0};
92     wsprintfW(endpoint, wszEndpointFormat, (DWORD)(*oxid >> 32),(DWORD)*oxid);
93 }
94
95 typedef struct
96 {
97     const IRpcChannelBufferVtbl *lpVtbl;
98     LONG                  refs;
99 } RpcChannelBuffer;
100
101 typedef struct
102 {
103     RpcChannelBuffer       super; /* superclass */
104
105     RPC_BINDING_HANDLE     bind; /* handle to the remote server */
106     OXID                   oxid; /* apartment in which the channel is valid */
107     DWORD                  server_pid; /* id of server process */
108     DWORD                  dest_context; /* returned from GetDestCtx */
109     LPVOID                 dest_context_data; /* returned from GetDestCtx */
110     HANDLE                 event; /* cached event handle */
111 } ClientRpcChannelBuffer;
112
113 struct dispatch_params
114 {
115     RPCOLEMESSAGE     *msg; /* message */
116     IRpcStubBuffer    *stub; /* stub buffer, if applicable */
117     IRpcChannelBuffer *chan; /* server channel buffer, if applicable */
118     IID                iid; /* ID of interface being called */
119     IUnknown          *iface; /* interface being called */
120     HANDLE             handle; /* handle that will become signaled when call finishes */
121     BOOL               bypass_rpcrt; /* bypass RPC runtime? */
122     RPC_STATUS         status; /* status (out) */
123     HRESULT            hr; /* hresult (out) */
124 };
125
126 struct message_state
127 {
128     RPC_BINDING_HANDLE binding_handle;
129     ULONG prefix_data_len;
130     SChannelHookCallInfo channel_hook_info;
131     BOOL bypass_rpcrt;
132
133     /* client only */
134     HWND target_hwnd;
135     DWORD target_tid;
136     struct dispatch_params params;
137 };
138
139 typedef struct
140 {
141     ULONG conformance; /* NDR */
142     GUID id;
143     ULONG size;
144     /* [size_is((size+7)&~7)] */ unsigned char data[1];
145 } WIRE_ORPC_EXTENT;
146
147 typedef struct
148 {
149     ULONG size;
150     ULONG reserved;
151     unsigned char extent[1];
152 } WIRE_ORPC_EXTENT_ARRAY;
153
154 typedef struct
155 {
156     ULONG version;
157     ULONG flags;
158     ULONG reserved1;
159     GUID  cid;
160     unsigned char extensions[1];
161 } WIRE_ORPCTHIS;
162
163 typedef struct
164 {
165     ULONG flags;
166     unsigned char extensions[1];
167 } WIRE_ORPCTHAT;
168
169 struct channel_hook_entry
170 {
171     struct list entry;
172     GUID id;
173     IChannelHook *hook;
174 };
175
176 struct channel_hook_buffer_data
177 {
178     GUID id;
179     ULONG extension_size;
180 };
181
182
183 static HRESULT unmarshal_ORPCTHAT(RPC_MESSAGE *msg, ORPCTHAT *orpcthat,
184                                   ORPC_EXTENT_ARRAY *orpc_ext_array, WIRE_ORPC_EXTENT **first_wire_orpc_extent);
185
186 /* Channel Hook Functions */
187
188 static ULONG ChannelHooks_ClientGetSize(SChannelHookCallInfo *info,
189     struct channel_hook_buffer_data **data, unsigned int *hook_count,
190     ULONG *extension_count)
191 {
192     struct channel_hook_entry *entry;
193     ULONG total_size = 0;
194     unsigned int hook_index = 0;
195
196     *hook_count = 0;
197     *extension_count = 0;
198
199     EnterCriticalSection(&csChannelHook);
200
201     LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
202         (*hook_count)++;
203
204     if (*hook_count)
205         *data = HeapAlloc(GetProcessHeap(), 0, *hook_count * sizeof(struct channel_hook_buffer_data));
206     else
207         *data = NULL;
208
209     LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
210     {
211         ULONG extension_size = 0;
212
213         IChannelHook_ClientGetSize(entry->hook, &entry->id, &info->iid, &extension_size);
214
215         TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size);
216
217         extension_size = (extension_size+7)&~7;
218         (*data)[hook_index].id = entry->id;
219         (*data)[hook_index].extension_size = extension_size;
220
221         /* an extension is only put onto the wire if it has data to write */
222         if (extension_size)
223         {
224             total_size += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[extension_size]);
225             (*extension_count)++;
226         }
227
228         hook_index++;
229     }
230
231     LeaveCriticalSection(&csChannelHook);
232
233     return total_size;
234 }
235
236 static unsigned char * ChannelHooks_ClientFillBuffer(SChannelHookCallInfo *info,
237     unsigned char *buffer, struct channel_hook_buffer_data *data,
238     unsigned int hook_count)
239 {
240     struct channel_hook_entry *entry;
241
242     EnterCriticalSection(&csChannelHook);
243
244     LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
245     {
246         unsigned int i;
247         ULONG extension_size = 0;
248         WIRE_ORPC_EXTENT *wire_orpc_extent = (WIRE_ORPC_EXTENT *)buffer;
249
250         for (i = 0; i < hook_count; i++)
251             if (IsEqualGUID(&entry->id, &data[i].id))
252                 extension_size = data[i].extension_size;
253
254         /* an extension is only put onto the wire if it has data to write */
255         if (!extension_size)
256             continue;
257
258         IChannelHook_ClientFillBuffer(entry->hook, &entry->id, &info->iid,
259             &extension_size, buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]));
260
261         TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size);
262
263         /* FIXME: set unused portion of wire_orpc_extent->data to 0? */
264
265         wire_orpc_extent->conformance = (extension_size+7)&~7;
266         wire_orpc_extent->size = extension_size;
267         wire_orpc_extent->id = entry->id;
268         buffer += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[wire_orpc_extent->conformance]);
269     }
270
271     LeaveCriticalSection(&csChannelHook);
272
273     return buffer;
274 }
275
276 static void ChannelHooks_ServerNotify(SChannelHookCallInfo *info,
277     DWORD lDataRep, WIRE_ORPC_EXTENT *first_wire_orpc_extent,
278     ULONG extension_count)
279 {
280     struct channel_hook_entry *entry;
281     ULONG i;
282
283     EnterCriticalSection(&csChannelHook);
284
285     LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
286     {
287         WIRE_ORPC_EXTENT *wire_orpc_extent;
288         for (i = 0, wire_orpc_extent = first_wire_orpc_extent;
289              i < extension_count;
290              i++, wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance])
291         {
292             if (IsEqualGUID(&entry->id, &wire_orpc_extent->id))
293                 break;
294         }
295         if (i == extension_count) wire_orpc_extent = NULL;
296
297         IChannelHook_ServerNotify(entry->hook, &entry->id, &info->iid,
298             wire_orpc_extent ? wire_orpc_extent->size : 0,
299             wire_orpc_extent ? wire_orpc_extent->data : NULL,
300             lDataRep);
301     }
302
303     LeaveCriticalSection(&csChannelHook);
304 }
305
306 static ULONG ChannelHooks_ServerGetSize(SChannelHookCallInfo *info,
307                                         struct channel_hook_buffer_data **data, unsigned int *hook_count,
308                                         ULONG *extension_count)
309 {
310     struct channel_hook_entry *entry;
311     ULONG total_size = 0;
312     unsigned int hook_index = 0;
313
314     *hook_count = 0;
315     *extension_count = 0;
316
317     EnterCriticalSection(&csChannelHook);
318
319     LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
320         (*hook_count)++;
321
322     if (*hook_count)
323         *data = HeapAlloc(GetProcessHeap(), 0, *hook_count * sizeof(struct channel_hook_buffer_data));
324     else
325         *data = NULL;
326
327     LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
328     {
329         ULONG extension_size = 0;
330
331         IChannelHook_ServerGetSize(entry->hook, &entry->id, &info->iid, S_OK,
332                                    &extension_size);
333
334         TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size);
335
336         extension_size = (extension_size+7)&~7;
337         (*data)[hook_index].id = entry->id;
338         (*data)[hook_index].extension_size = extension_size;
339
340         /* an extension is only put onto the wire if it has data to write */
341         if (extension_size)
342         {
343             total_size += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[extension_size]);
344             (*extension_count)++;
345         }
346
347         hook_index++;
348     }
349
350     LeaveCriticalSection(&csChannelHook);
351
352     return total_size;
353 }
354
355 static unsigned char * ChannelHooks_ServerFillBuffer(SChannelHookCallInfo *info,
356                                                      unsigned char *buffer, struct channel_hook_buffer_data *data,
357                                                      unsigned int hook_count)
358 {
359     struct channel_hook_entry *entry;
360
361     EnterCriticalSection(&csChannelHook);
362
363     LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
364     {
365         unsigned int i;
366         ULONG extension_size = 0;
367         WIRE_ORPC_EXTENT *wire_orpc_extent = (WIRE_ORPC_EXTENT *)buffer;
368
369         for (i = 0; i < hook_count; i++)
370             if (IsEqualGUID(&entry->id, &data[i].id))
371                 extension_size = data[i].extension_size;
372
373         /* an extension is only put onto the wire if it has data to write */
374         if (!extension_size)
375             continue;
376
377         IChannelHook_ServerFillBuffer(entry->hook, &entry->id, &info->iid,
378                                       &extension_size, buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]),
379                                       S_OK);
380
381         TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size);
382
383         /* FIXME: set unused portion of wire_orpc_extent->data to 0? */
384
385         wire_orpc_extent->conformance = (extension_size+7)&~7;
386         wire_orpc_extent->size = extension_size;
387         wire_orpc_extent->id = entry->id;
388         buffer += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[wire_orpc_extent->conformance]);
389     }
390
391     LeaveCriticalSection(&csChannelHook);
392
393     return buffer;
394 }
395
396 static void ChannelHooks_ClientNotify(SChannelHookCallInfo *info,
397                                       DWORD lDataRep, WIRE_ORPC_EXTENT *first_wire_orpc_extent,
398                                       ULONG extension_count, HRESULT hrFault)
399 {
400     struct channel_hook_entry *entry;
401     ULONG i;
402
403     EnterCriticalSection(&csChannelHook);
404
405     LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
406     {
407         WIRE_ORPC_EXTENT *wire_orpc_extent;
408         for (i = 0, wire_orpc_extent = first_wire_orpc_extent;
409              i < extension_count;
410              i++, wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance])
411         {
412             if (IsEqualGUID(&entry->id, &wire_orpc_extent->id))
413                 break;
414         }
415         if (i == extension_count) wire_orpc_extent = NULL;
416
417         IChannelHook_ClientNotify(entry->hook, &entry->id, &info->iid,
418                                   wire_orpc_extent ? wire_orpc_extent->size : 0,
419                                   wire_orpc_extent ? wire_orpc_extent->data : NULL,
420                                   lDataRep, hrFault);
421     }
422
423     LeaveCriticalSection(&csChannelHook);
424 }
425
426 HRESULT RPC_RegisterChannelHook(REFGUID rguid, IChannelHook *hook)
427 {
428     struct channel_hook_entry *entry;
429
430     TRACE("(%s, %p)\n", debugstr_guid(rguid), hook);
431
432     entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
433     if (!entry)
434         return E_OUTOFMEMORY;
435
436     entry->id = *rguid;
437     entry->hook = hook;
438     IChannelHook_AddRef(hook);
439
440     EnterCriticalSection(&csChannelHook);
441     list_add_tail(&channel_hooks, &entry->entry);
442     LeaveCriticalSection(&csChannelHook);
443
444     return S_OK;
445 }
446
447 void RPC_UnregisterAllChannelHooks(void)
448 {
449     struct channel_hook_entry *cursor;
450     struct channel_hook_entry *cursor2;
451
452     EnterCriticalSection(&csChannelHook);
453     LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &channel_hooks, struct channel_hook_entry, entry)
454         HeapFree(GetProcessHeap(), 0, cursor);
455     LeaveCriticalSection(&csChannelHook);
456 }
457
458 /* RPC Channel Buffer Functions */
459
460 static HRESULT WINAPI RpcChannelBuffer_QueryInterface(LPRPCCHANNELBUFFER iface, REFIID riid, LPVOID *ppv)
461 {
462     *ppv = NULL;
463     if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown))
464     {
465         *ppv = iface;
466         IUnknown_AddRef(iface);
467         return S_OK;
468     }
469     return E_NOINTERFACE;
470 }
471
472 static ULONG WINAPI RpcChannelBuffer_AddRef(LPRPCCHANNELBUFFER iface)
473 {
474     RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
475     return InterlockedIncrement(&This->refs);
476 }
477
478 static ULONG WINAPI ServerRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface)
479 {
480     RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
481     ULONG ref;
482
483     ref = InterlockedDecrement(&This->refs);
484     if (ref)
485         return ref;
486
487     HeapFree(GetProcessHeap(), 0, This);
488     return 0;
489 }
490
491 static ULONG WINAPI ClientRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface)
492 {
493     ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
494     ULONG ref;
495
496     ref = InterlockedDecrement(&This->super.refs);
497     if (ref)
498         return ref;
499
500     if (This->event) CloseHandle(This->event);
501     RpcBindingFree(&This->bind);
502     HeapFree(GetProcessHeap(), 0, This);
503     return 0;
504 }
505
506 static HRESULT WINAPI ServerRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
507 {
508     RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
509     RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
510     RPC_STATUS status;
511     ORPCTHAT *orpcthat;
512     struct message_state *message_state;
513     ULONG extensions_size;
514     struct channel_hook_buffer_data *channel_hook_data;
515     unsigned int channel_hook_count;
516     ULONG extension_count;
517
518     TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid));
519
520     message_state = msg->Handle;
521     /* restore the binding handle and the real start of data */
522     msg->Handle = message_state->binding_handle;
523     msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
524
525     extensions_size = ChannelHooks_ServerGetSize(&message_state->channel_hook_info,
526                                                  &channel_hook_data, &channel_hook_count, &extension_count);
527
528     msg->BufferLength += FIELD_OFFSET(WIRE_ORPCTHAT, extensions) + sizeof(DWORD);
529     if (extensions_size)
530     {
531         msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent[2*sizeof(DWORD) + extensions_size]);
532         if (extension_count & 1)
533             msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
534     }
535
536     if (message_state->bypass_rpcrt)
537     {
538         msg->Buffer = HeapAlloc(GetProcessHeap(), 0, msg->BufferLength);
539         if (msg->Buffer)
540             status = RPC_S_OK;
541         else
542             status = ERROR_OUTOFMEMORY;
543     }
544     else
545         status = I_RpcGetBuffer(msg);
546
547     orpcthat = msg->Buffer;
548     msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPCTHAT, extensions);
549
550     orpcthat->flags = ORPCF_NULL /* FIXME? */;
551
552     /* NDR representation of orpcthat->extensions */
553     *(DWORD *)msg->Buffer = extensions_size ? 1 : 0;
554     msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
555
556     if (extensions_size)
557     {
558         WIRE_ORPC_EXTENT_ARRAY *orpc_extent_array = msg->Buffer;
559         orpc_extent_array->size = extension_count;
560         orpc_extent_array->reserved = 0;
561         msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent);
562         /* NDR representation of orpc_extent_array->extent */
563         *(DWORD *)msg->Buffer = 1;
564         msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
565         /* NDR representation of [size_is] attribute of orpc_extent_array->extent */
566         *(DWORD *)msg->Buffer = (extension_count + 1) & ~1;
567         msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
568
569         msg->Buffer = ChannelHooks_ServerFillBuffer(&message_state->channel_hook_info,
570                                                     msg->Buffer, channel_hook_data, channel_hook_count);
571
572         /* we must add a dummy extension if there is an odd extension
573          * count to meet the contract specified by the size_is attribute */
574         if (extension_count & 1)
575         {
576             WIRE_ORPC_EXTENT *wire_orpc_extent = msg->Buffer;
577             wire_orpc_extent->conformance = 0;
578             wire_orpc_extent->id = GUID_NULL;
579             wire_orpc_extent->size = 0;
580             msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
581         }
582     }
583
584     HeapFree(GetProcessHeap(), 0, channel_hook_data);
585
586     /* store the prefixed data length so that we can restore the real buffer
587      * later */
588     message_state->prefix_data_len = (char *)msg->Buffer - (char *)orpcthat;
589     msg->BufferLength -= message_state->prefix_data_len;
590     /* save away the message state again */
591     msg->Handle = message_state;
592
593     TRACE("-- %d\n", status);
594
595     return HRESULT_FROM_WIN32(status);
596 }
597
598 static HANDLE ClientRpcChannelBuffer_GetEventHandle(ClientRpcChannelBuffer *This)
599 {
600     HANDLE event = InterlockedExchangePointer(&This->event, NULL);
601
602     /* Note: must be auto-reset event so we can reuse it without a call
603     * to ResetEvent */
604     if (!event) event = CreateEventW(NULL, FALSE, FALSE, NULL);
605
606     return event;
607 }
608
609 static void ClientRpcChannelBuffer_ReleaseEventHandle(ClientRpcChannelBuffer *This, HANDLE event)
610 {
611     if (InterlockedCompareExchangePointer(&This->event, event, NULL))
612         /* already a handle cached in This */
613         CloseHandle(event);
614 }
615
616 static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
617 {
618     ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
619     RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
620     RPC_CLIENT_INTERFACE *cif;
621     RPC_STATUS status;
622     ORPCTHIS *orpcthis;
623     struct message_state *message_state;
624     ULONG extensions_size;
625     struct channel_hook_buffer_data *channel_hook_data;
626     unsigned int channel_hook_count;
627     ULONG extension_count;
628     IPID ipid;
629     HRESULT hr;
630     APARTMENT *apt = NULL;
631
632     TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid));
633
634     cif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_CLIENT_INTERFACE));
635     if (!cif)
636         return E_OUTOFMEMORY;
637
638     message_state = HeapAlloc(GetProcessHeap(), 0, sizeof(*message_state));
639     if (!message_state)
640     {
641         HeapFree(GetProcessHeap(), 0, cif);
642         return E_OUTOFMEMORY;
643     }
644
645     cif->Length = sizeof(RPC_CLIENT_INTERFACE);
646     /* RPC interface ID = COM interface ID */
647     cif->InterfaceId.SyntaxGUID = *riid;
648     /* COM objects always have a version of 0.0 */
649     cif->InterfaceId.SyntaxVersion.MajorVersion = 0;
650     cif->InterfaceId.SyntaxVersion.MinorVersion = 0;
651     msg->Handle = This->bind;
652     msg->RpcInterfaceInformation = cif;
653
654     message_state->prefix_data_len = 0;
655     message_state->binding_handle = This->bind;
656
657     message_state->channel_hook_info.iid = *riid;
658     message_state->channel_hook_info.cbSize = sizeof(message_state->channel_hook_info);
659     message_state->channel_hook_info.uCausality = COM_CurrentCausalityId();
660     message_state->channel_hook_info.dwServerPid = This->server_pid;
661     message_state->channel_hook_info.iMethod = msg->ProcNum;
662     message_state->channel_hook_info.pObject = NULL; /* only present on server-side */
663     message_state->target_hwnd = NULL;
664     message_state->target_tid = 0;
665     memset(&message_state->params, 0, sizeof(message_state->params));
666
667     extensions_size = ChannelHooks_ClientGetSize(&message_state->channel_hook_info,
668         &channel_hook_data, &channel_hook_count, &extension_count);
669
670     msg->BufferLength += FIELD_OFFSET(WIRE_ORPCTHIS, extensions) + sizeof(DWORD);
671     if (extensions_size)
672     {
673         msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent[2*sizeof(DWORD) + extensions_size]);
674         if (extension_count & 1)
675             msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
676     }
677
678     RpcBindingInqObject(message_state->binding_handle, &ipid);
679     hr = ipid_get_dispatch_params(&ipid, &apt, &message_state->params.stub,
680                                   &message_state->params.chan,
681                                   &message_state->params.iid,
682                                   &message_state->params.iface);
683     if (hr == S_OK)
684     {
685         /* stub, chan, iface and iid are unneeded in multi-threaded case as we go
686          * via the RPC runtime */
687         if (apt->multi_threaded)
688         {
689             IRpcStubBuffer_Release(message_state->params.stub);
690             message_state->params.stub = NULL;
691             IRpcChannelBuffer_Release(message_state->params.chan);
692             message_state->params.chan = NULL;
693             message_state->params.iface = NULL;
694         }
695         else
696         {
697             message_state->params.bypass_rpcrt = TRUE;
698             message_state->target_hwnd = apartment_getwindow(apt);
699             message_state->target_tid = apt->tid;
700             /* we assume later on that this being non-NULL is the indicator that
701              * means call directly instead of going through RPC runtime */
702             if (!message_state->target_hwnd)
703                 ERR("window for apartment %s is NULL\n", wine_dbgstr_longlong(apt->oxid));
704         }
705     }
706     if (apt) apartment_release(apt);
707     message_state->params.handle = ClientRpcChannelBuffer_GetEventHandle(This);
708     /* Note: message_state->params.msg is initialised in
709      * ClientRpcChannelBuffer_SendReceive */
710
711     /* shortcut the RPC runtime */
712     if (message_state->target_hwnd)
713     {
714         msg->Buffer = HeapAlloc(GetProcessHeap(), 0, msg->BufferLength);
715         if (msg->Buffer)
716             status = RPC_S_OK;
717         else
718             status = ERROR_OUTOFMEMORY;
719     }
720     else
721         status = I_RpcGetBuffer(msg);
722
723     msg->Handle = message_state;
724
725     if (status == RPC_S_OK)
726     {
727         orpcthis = msg->Buffer;
728         msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPCTHIS, extensions);
729
730         orpcthis->version.MajorVersion = COM_MAJOR_VERSION;
731         orpcthis->version.MinorVersion = COM_MINOR_VERSION;
732         orpcthis->flags = message_state->channel_hook_info.dwServerPid ? ORPCF_LOCAL : ORPCF_NULL;
733         orpcthis->reserved1 = 0;
734         orpcthis->cid = message_state->channel_hook_info.uCausality;
735
736         /* NDR representation of orpcthis->extensions */
737         *(DWORD *)msg->Buffer = extensions_size ? 1 : 0;
738         msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
739
740         if (extensions_size)
741         {
742             ORPC_EXTENT_ARRAY *orpc_extent_array = msg->Buffer;
743             orpc_extent_array->size = extension_count;
744             orpc_extent_array->reserved = 0;
745             msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent);
746             /* NDR representation of orpc_extent_array->extent */
747             *(DWORD *)msg->Buffer = 1;
748             msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
749             /* NDR representation of [size_is] attribute of orpc_extent_array->extent */
750             *(DWORD *)msg->Buffer = (extension_count + 1) & ~1;
751             msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
752
753             msg->Buffer = ChannelHooks_ClientFillBuffer(&message_state->channel_hook_info,
754                 msg->Buffer, channel_hook_data, channel_hook_count);
755
756             /* we must add a dummy extension if there is an odd extension
757              * count to meet the contract specified by the size_is attribute */
758             if (extension_count & 1)
759             {
760                 WIRE_ORPC_EXTENT *wire_orpc_extent = msg->Buffer;
761                 wire_orpc_extent->conformance = 0;
762                 wire_orpc_extent->id = GUID_NULL;
763                 wire_orpc_extent->size = 0;
764                 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
765             }
766         }
767
768         /* store the prefixed data length so that we can restore the real buffer
769          * pointer in ClientRpcChannelBuffer_SendReceive. */
770         message_state->prefix_data_len = (char *)msg->Buffer - (char *)orpcthis;
771         msg->BufferLength -= message_state->prefix_data_len;
772     }
773
774     HeapFree(GetProcessHeap(), 0, channel_hook_data);
775
776     TRACE("-- %d\n", status);
777
778     return HRESULT_FROM_WIN32(status);
779 }
780
781 static HRESULT WINAPI ServerRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus)
782 {
783     FIXME("stub\n");
784     return E_NOTIMPL;
785 }
786
787 /* this thread runs an outgoing RPC */
788 static DWORD WINAPI rpc_sendreceive_thread(LPVOID param)
789 {
790     struct dispatch_params *data = param;
791
792     /* Note: I_RpcSendReceive doesn't raise exceptions like the higher-level
793      * RPC functions do */
794     data->status = I_RpcSendReceive((RPC_MESSAGE *)data->msg);
795
796     TRACE("completed with status 0x%x\n", data->status);
797
798     SetEvent(data->handle);
799
800     return 0;
801 }
802
803 static inline HRESULT ClientRpcChannelBuffer_IsCorrectApartment(ClientRpcChannelBuffer *This, APARTMENT *apt)
804 {
805     OXID oxid;
806     if (!apt)
807         return S_FALSE;
808     if (apartment_getoxid(apt, &oxid) != S_OK)
809         return S_FALSE;
810     if (This->oxid != oxid)
811         return S_FALSE;
812     return S_OK;
813 }
814
815 static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus)
816 {
817     ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
818     HRESULT hr;
819     RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
820     RPC_STATUS status;
821     DWORD index;
822     struct message_state *message_state;
823     ORPCTHAT orpcthat;
824     ORPC_EXTENT_ARRAY orpc_ext_array;
825     WIRE_ORPC_EXTENT *first_wire_orpc_extent = NULL;
826     HRESULT hrFault = S_OK;
827
828     TRACE("(%p) iMethod=%d\n", olemsg, olemsg->iMethod);
829
830     hr = ClientRpcChannelBuffer_IsCorrectApartment(This, COM_CurrentApt());
831     if (hr != S_OK)
832     {
833         ERR("called from wrong apartment, should have been 0x%s\n",
834             wine_dbgstr_longlong(This->oxid));
835         return RPC_E_WRONG_THREAD;
836     }
837     /* This situation should be impossible in multi-threaded apartments,
838      * because the calling thread isn't re-enterable.
839      * Note: doing a COM call during the processing of a sent message is
840      * only disallowed if a client call is already being waited for
841      * completion */
842     if (!COM_CurrentApt()->multi_threaded &&
843         COM_CurrentInfo()->pending_call_count_client &&
844         InSendMessage())
845     {
846         ERR("can't make an outgoing COM call in response to a sent message\n");
847         return RPC_E_CANTCALLOUT_ININPUTSYNCCALL;
848     }
849
850     message_state = msg->Handle;
851     /* restore the binding handle and the real start of data */
852     msg->Handle = message_state->binding_handle;
853     msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
854     msg->BufferLength += message_state->prefix_data_len;
855
856     /* Note: this is an optimization in the Microsoft OLE runtime that we need
857      * to copy, as shown by the test_no_couninitialize_client test. without
858      * short-circuiting the RPC runtime in the case below, the test will
859      * deadlock on the loader lock due to the RPC runtime needing to create
860      * a thread to process the RPC when this function is called indirectly
861      * from DllMain */
862
863     message_state->params.msg = olemsg;
864     if (message_state->params.bypass_rpcrt)
865     {
866         TRACE("Calling apartment thread 0x%08x...\n", message_state->target_tid);
867
868         msg->ProcNum &= ~RPC_FLAGS_VALID_BIT;
869
870         if (!PostMessageW(message_state->target_hwnd, DM_EXECUTERPC, 0,
871                           (LPARAM)&message_state->params))
872         {
873             ERR("PostMessage failed with error %u\n", GetLastError());
874
875             /* Note: message_state->params.iface doesn't have a reference and
876              * so doesn't need to be released */
877
878             hr = HRESULT_FROM_WIN32(GetLastError());
879         }
880     }
881     else
882     {
883         /* we use a separate thread here because we need to be able to
884          * pump the message loop in the application thread: if we do not,
885          * any windows created by this thread will hang and RPCs that try
886          * and re-enter this STA from an incoming server thread will
887          * deadlock. InstallShield is an example of that.
888          */
889         if (!QueueUserWorkItem(rpc_sendreceive_thread, &message_state->params, WT_EXECUTEDEFAULT))
890         {
891             ERR("QueueUserWorkItem failed with error %u\n", GetLastError());
892             hr = E_UNEXPECTED;
893         }
894         else
895             hr = S_OK;
896     }
897
898     if (hr == S_OK)
899     {
900         if (WaitForSingleObject(message_state->params.handle, 0))
901         {
902             COM_CurrentInfo()->pending_call_count_client++;
903             hr = CoWaitForMultipleHandles(0, INFINITE, 1, &message_state->params.handle, &index);
904             COM_CurrentInfo()->pending_call_count_client--;
905         }
906     }
907     ClientRpcChannelBuffer_ReleaseEventHandle(This, message_state->params.handle);
908
909     /* for WM shortcut, faults are returned in params->hr */
910     if (hr == S_OK)
911         hrFault = message_state->params.hr;
912
913     status = message_state->params.status;
914
915     orpcthat.flags = ORPCF_NULL;
916     orpcthat.extensions = NULL;
917
918     TRACE("RPC call status: 0x%x\n", status);
919     if (status != RPC_S_OK)
920         hr = HRESULT_FROM_WIN32(status);
921
922     TRACE("hrFault = 0x%08x\n", hrFault);
923
924     /* FIXME: this condition should be
925      * "hr == S_OK && (!hrFault || msg->BufferLength > FIELD_OFFSET(ORPCTHAT, extensions) + 4)"
926      * but we don't currently reset the message length for PostMessage
927      * dispatched calls */
928     if (hr == S_OK && hrFault == S_OK)
929     {
930         HRESULT hr2;
931         char *original_buffer = msg->Buffer;
932
933         /* handle ORPCTHAT and client extensions */
934
935         hr2 = unmarshal_ORPCTHAT(msg, &orpcthat, &orpc_ext_array, &first_wire_orpc_extent);
936         if (FAILED(hr2))
937             hr = hr2;
938
939         message_state->prefix_data_len = (char *)msg->Buffer - original_buffer;
940         msg->BufferLength -= message_state->prefix_data_len;
941     }
942     else
943         message_state->prefix_data_len = 0;
944
945     if (hr == S_OK)
946     {
947         ChannelHooks_ClientNotify(&message_state->channel_hook_info,
948                                   msg->DataRepresentation,
949                                   first_wire_orpc_extent,
950                                   orpcthat.extensions && first_wire_orpc_extent ? orpcthat.extensions->size : 0,
951                                   hrFault);
952     }
953
954     /* save away the message state again */
955     msg->Handle = message_state;
956
957     if (pstatus) *pstatus = status;
958
959     if (hr == S_OK)
960         hr = hrFault;
961
962     TRACE("-- 0x%08x\n", hr);
963
964     return hr;
965 }
966
967 static HRESULT WINAPI ServerRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
968 {
969     RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
970     RPC_STATUS status;
971     struct message_state *message_state;
972
973     TRACE("(%p)\n", msg);
974
975     message_state = msg->Handle;
976     /* restore the binding handle and the real start of data */
977     msg->Handle = message_state->binding_handle;
978     msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
979     msg->BufferLength += message_state->prefix_data_len;
980     message_state->prefix_data_len = 0;
981
982     if (message_state->bypass_rpcrt)
983     {
984         HeapFree(GetProcessHeap(), 0, msg->Buffer);
985         status = RPC_S_OK;
986     }
987     else
988         status = I_RpcFreeBuffer(msg);
989
990     msg->Handle = message_state;
991
992     TRACE("-- %d\n", status);
993
994     return HRESULT_FROM_WIN32(status);
995 }
996
997 static HRESULT WINAPI ClientRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
998 {
999     RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
1000     RPC_STATUS status;
1001     struct message_state *message_state;
1002
1003     TRACE("(%p)\n", msg);
1004
1005     message_state = msg->Handle;
1006     /* restore the binding handle and the real start of data */
1007     msg->Handle = message_state->binding_handle;
1008     msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
1009     msg->BufferLength += message_state->prefix_data_len;
1010
1011     if (message_state->params.bypass_rpcrt)
1012     {
1013         HeapFree(GetProcessHeap(), 0, msg->Buffer);
1014         status = RPC_S_OK;
1015     }
1016     else
1017         status = I_RpcFreeBuffer(msg);
1018
1019     HeapFree(GetProcessHeap(), 0, msg->RpcInterfaceInformation);
1020     msg->RpcInterfaceInformation = NULL;
1021
1022     if (message_state->params.stub)
1023         IRpcStubBuffer_Release(message_state->params.stub);
1024     if (message_state->params.chan)
1025         IRpcChannelBuffer_Release(message_state->params.chan);
1026     HeapFree(GetProcessHeap(), 0, message_state);
1027
1028     TRACE("-- %d\n", status);
1029
1030     return HRESULT_FROM_WIN32(status);
1031 }
1032
1033 static HRESULT WINAPI ClientRpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext)
1034 {
1035     ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
1036
1037     TRACE("(%p,%p)\n", pdwDestContext, ppvDestContext);
1038
1039     *pdwDestContext = This->dest_context;
1040     *ppvDestContext = This->dest_context_data;
1041
1042     return S_OK;
1043 }
1044
1045 static HRESULT WINAPI ServerRpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext)
1046 {
1047     WARN("(%p,%p), stub!\n", pdwDestContext, ppvDestContext);
1048
1049     /* FIXME: implement this by storing the dwDestContext and pvDestContext
1050      * values passed into IMarshal_MarshalInterface and returning them here */
1051     *pdwDestContext = MSHCTX_DIFFERENTMACHINE;
1052     *ppvDestContext = NULL;
1053     return S_OK;
1054 }
1055
1056 static HRESULT WINAPI RpcChannelBuffer_IsConnected(LPRPCCHANNELBUFFER iface)
1057 {
1058     TRACE("()\n");
1059     /* native does nothing too */
1060     return S_OK;
1061 }
1062
1063 static const IRpcChannelBufferVtbl ClientRpcChannelBufferVtbl =
1064 {
1065     RpcChannelBuffer_QueryInterface,
1066     RpcChannelBuffer_AddRef,
1067     ClientRpcChannelBuffer_Release,
1068     ClientRpcChannelBuffer_GetBuffer,
1069     ClientRpcChannelBuffer_SendReceive,
1070     ClientRpcChannelBuffer_FreeBuffer,
1071     ClientRpcChannelBuffer_GetDestCtx,
1072     RpcChannelBuffer_IsConnected
1073 };
1074
1075 static const IRpcChannelBufferVtbl ServerRpcChannelBufferVtbl =
1076 {
1077     RpcChannelBuffer_QueryInterface,
1078     RpcChannelBuffer_AddRef,
1079     ServerRpcChannelBuffer_Release,
1080     ServerRpcChannelBuffer_GetBuffer,
1081     ServerRpcChannelBuffer_SendReceive,
1082     ServerRpcChannelBuffer_FreeBuffer,
1083     ServerRpcChannelBuffer_GetDestCtx,
1084     RpcChannelBuffer_IsConnected
1085 };
1086
1087 /* returns a channel buffer for proxies */
1088 HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid,
1089                                 const OXID_INFO *oxid_info,
1090                                 DWORD dest_context, void *dest_context_data,
1091                                 IRpcChannelBuffer **chan)
1092 {
1093     ClientRpcChannelBuffer *This;
1094     WCHAR                   endpoint[200];
1095     RPC_BINDING_HANDLE      bind;
1096     RPC_STATUS              status;
1097     LPWSTR                  string_binding;
1098
1099     /* FIXME: get the endpoint from oxid_info->psa instead */
1100     get_rpc_endpoint(endpoint, oxid);
1101
1102     TRACE("proxy pipe: connecting to endpoint: %s\n", debugstr_w(endpoint));
1103
1104     status = RpcStringBindingComposeW(
1105         NULL,
1106         wszRpcTransport,
1107         NULL,
1108         endpoint,
1109         NULL,
1110         &string_binding);
1111         
1112     if (status == RPC_S_OK)
1113     {
1114         status = RpcBindingFromStringBindingW(string_binding, &bind);
1115
1116         if (status == RPC_S_OK)
1117         {
1118             IPID ipid2 = *ipid; /* why can't RpcBindingSetObject take a const? */
1119             status = RpcBindingSetObject(bind, &ipid2);
1120             if (status != RPC_S_OK)
1121                 RpcBindingFree(&bind);
1122         }
1123
1124         RpcStringFreeW(&string_binding);
1125     }
1126
1127     if (status != RPC_S_OK)
1128     {
1129         ERR("Couldn't get binding for endpoint %s, status = %d\n", debugstr_w(endpoint), status);
1130         return HRESULT_FROM_WIN32(status);
1131     }
1132
1133     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1134     if (!This)
1135     {
1136         RpcBindingFree(&bind);
1137         return E_OUTOFMEMORY;
1138     }
1139
1140     This->super.lpVtbl = &ClientRpcChannelBufferVtbl;
1141     This->super.refs = 1;
1142     This->bind = bind;
1143     apartment_getoxid(COM_CurrentApt(), &This->oxid);
1144     This->server_pid = oxid_info->dwPid;
1145     This->dest_context = dest_context;
1146     This->dest_context_data = dest_context_data;
1147     This->event = NULL;
1148
1149     *chan = (IRpcChannelBuffer*)This;
1150
1151     return S_OK;
1152 }
1153
1154 HRESULT RPC_CreateServerChannel(IRpcChannelBuffer **chan)
1155 {
1156     RpcChannelBuffer *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1157     if (!This)
1158         return E_OUTOFMEMORY;
1159
1160     This->lpVtbl = &ServerRpcChannelBufferVtbl;
1161     This->refs = 1;
1162     
1163     *chan = (IRpcChannelBuffer*)This;
1164
1165     return S_OK;
1166 }
1167
1168 /* unmarshals ORPC_EXTENT_ARRAY according to NDR rules, but doesn't allocate
1169  * any memory */
1170 static HRESULT unmarshal_ORPC_EXTENT_ARRAY(RPC_MESSAGE *msg, const char *end,
1171                                            ORPC_EXTENT_ARRAY *extensions,
1172                                            WIRE_ORPC_EXTENT **first_wire_orpc_extent)
1173 {
1174     DWORD pointer_id;
1175     DWORD i;
1176
1177     memcpy(extensions, msg->Buffer, FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent));
1178     msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent);
1179
1180     if ((const char *)msg->Buffer + 2 * sizeof(DWORD) > end)
1181         return RPC_E_INVALID_HEADER;
1182
1183     pointer_id = *(DWORD *)msg->Buffer;
1184     msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
1185     extensions->extent = NULL;
1186
1187     if (pointer_id)
1188     {
1189         WIRE_ORPC_EXTENT *wire_orpc_extent;
1190
1191         /* conformance */
1192         if (*(DWORD *)msg->Buffer != ((extensions->size+1)&~1))
1193             return RPC_S_INVALID_BOUND;
1194
1195         msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
1196
1197         /* arbitrary limit for security (don't know what native does) */
1198         if (extensions->size > 256)
1199         {
1200             ERR("too many extensions: %d\n", extensions->size);
1201             return RPC_S_INVALID_BOUND;
1202         }
1203
1204         *first_wire_orpc_extent = wire_orpc_extent = msg->Buffer;
1205         for (i = 0; i < ((extensions->size+1)&~1); i++)
1206         {
1207             if ((const char *)&wire_orpc_extent->data[0] > end)
1208                 return RPC_S_INVALID_BOUND;
1209             if (wire_orpc_extent->conformance != ((wire_orpc_extent->size+7)&~7))
1210                 return RPC_S_INVALID_BOUND;
1211             if ((const char *)&wire_orpc_extent->data[wire_orpc_extent->conformance] > end)
1212                 return RPC_S_INVALID_BOUND;
1213             TRACE("size %u, guid %s\n", wire_orpc_extent->size, debugstr_guid(&wire_orpc_extent->id));
1214             wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance];
1215         }
1216         msg->Buffer = wire_orpc_extent;
1217     }
1218
1219     return S_OK;
1220 }
1221
1222 /* unmarshals ORPCTHIS according to NDR rules, but doesn't allocate any memory */
1223 static HRESULT unmarshal_ORPCTHIS(RPC_MESSAGE *msg, ORPCTHIS *orpcthis,
1224     ORPC_EXTENT_ARRAY *orpc_ext_array, WIRE_ORPC_EXTENT **first_wire_orpc_extent)
1225 {
1226     const char *end = (char *)msg->Buffer + msg->BufferLength;
1227
1228     *first_wire_orpc_extent = NULL;
1229
1230     if (msg->BufferLength < FIELD_OFFSET(WIRE_ORPCTHIS, extensions) + sizeof(DWORD))
1231     {
1232         ERR("invalid buffer length\n");
1233         return RPC_E_INVALID_HEADER;
1234     }
1235
1236     memcpy(orpcthis, msg->Buffer, FIELD_OFFSET(WIRE_ORPCTHIS, extensions));
1237     msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPCTHIS, extensions);
1238
1239     if ((const char *)msg->Buffer + sizeof(DWORD) > end)
1240         return RPC_E_INVALID_HEADER;
1241
1242     if (*(DWORD *)msg->Buffer)
1243         orpcthis->extensions = orpc_ext_array;
1244     else
1245         orpcthis->extensions = NULL;
1246
1247     msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
1248
1249     if (orpcthis->extensions)
1250     {
1251         HRESULT hr = unmarshal_ORPC_EXTENT_ARRAY(msg, end, orpc_ext_array,
1252                                                  first_wire_orpc_extent);
1253         if (FAILED(hr))
1254             return hr;
1255     }
1256
1257     if ((orpcthis->version.MajorVersion != COM_MAJOR_VERSION) ||
1258         (orpcthis->version.MinorVersion > COM_MINOR_VERSION))
1259     {
1260         ERR("COM version {%d, %d} not supported\n",
1261             orpcthis->version.MajorVersion, orpcthis->version.MinorVersion);
1262         return RPC_E_VERSION_MISMATCH;
1263     }
1264
1265     if (orpcthis->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4))
1266     {
1267         ERR("invalid flags 0x%x\n", orpcthis->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4));
1268         return RPC_E_INVALID_HEADER;
1269     }
1270
1271     return S_OK;
1272 }
1273
1274 static HRESULT unmarshal_ORPCTHAT(RPC_MESSAGE *msg, ORPCTHAT *orpcthat,
1275                                   ORPC_EXTENT_ARRAY *orpc_ext_array, WIRE_ORPC_EXTENT **first_wire_orpc_extent)
1276 {
1277     const char *end = (char *)msg->Buffer + msg->BufferLength;
1278
1279     *first_wire_orpc_extent = NULL;
1280
1281     if (msg->BufferLength < FIELD_OFFSET(WIRE_ORPCTHAT, extensions) + sizeof(DWORD))
1282     {
1283         ERR("invalid buffer length\n");
1284         return RPC_E_INVALID_HEADER;
1285     }
1286
1287     memcpy(orpcthat, msg->Buffer, FIELD_OFFSET(WIRE_ORPCTHAT, extensions));
1288     msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPCTHAT, extensions);
1289
1290     if ((const char *)msg->Buffer + sizeof(DWORD) > end)
1291         return RPC_E_INVALID_HEADER;
1292
1293     if (*(DWORD *)msg->Buffer)
1294         orpcthat->extensions = orpc_ext_array;
1295     else
1296         orpcthat->extensions = NULL;
1297
1298     msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
1299
1300     if (orpcthat->extensions)
1301     {
1302         HRESULT hr = unmarshal_ORPC_EXTENT_ARRAY(msg, end, orpc_ext_array,
1303                                                  first_wire_orpc_extent);
1304         if (FAILED(hr))
1305             return hr;
1306     }
1307
1308     if (orpcthat->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4))
1309     {
1310         ERR("invalid flags 0x%x\n", orpcthat->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4));
1311         return RPC_E_INVALID_HEADER;
1312     }
1313
1314     return S_OK;
1315 }
1316
1317 void RPC_ExecuteCall(struct dispatch_params *params)
1318 {
1319     struct message_state *message_state = NULL;
1320     RPC_MESSAGE *msg = (RPC_MESSAGE *)params->msg;
1321     char *original_buffer = msg->Buffer;
1322     ORPCTHIS orpcthis;
1323     ORPC_EXTENT_ARRAY orpc_ext_array;
1324     WIRE_ORPC_EXTENT *first_wire_orpc_extent;
1325     GUID old_causality_id;
1326
1327     /* handle ORPCTHIS and server extensions */
1328
1329     params->hr = unmarshal_ORPCTHIS(msg, &orpcthis, &orpc_ext_array, &first_wire_orpc_extent);
1330     if (params->hr != S_OK)
1331     {
1332         msg->Buffer = original_buffer;
1333         goto exit;
1334     }
1335
1336     message_state = HeapAlloc(GetProcessHeap(), 0, sizeof(*message_state));
1337     if (!message_state)
1338     {
1339         params->hr = E_OUTOFMEMORY;
1340         msg->Buffer = original_buffer;
1341         goto exit;
1342     }
1343
1344     message_state->prefix_data_len = (char *)msg->Buffer - original_buffer;
1345     message_state->binding_handle = msg->Handle;
1346     message_state->bypass_rpcrt = params->bypass_rpcrt;
1347
1348     message_state->channel_hook_info.iid = params->iid;
1349     message_state->channel_hook_info.cbSize = sizeof(message_state->channel_hook_info);
1350     message_state->channel_hook_info.uCausality = orpcthis.cid;
1351     message_state->channel_hook_info.dwServerPid = GetCurrentProcessId();
1352     message_state->channel_hook_info.iMethod = msg->ProcNum;
1353     message_state->channel_hook_info.pObject = params->iface;
1354
1355     if (orpcthis.extensions && first_wire_orpc_extent &&
1356         orpcthis.extensions->size)
1357         ChannelHooks_ServerNotify(&message_state->channel_hook_info, msg->DataRepresentation, first_wire_orpc_extent, orpcthis.extensions->size);
1358
1359     msg->Handle = message_state;
1360     msg->BufferLength -= message_state->prefix_data_len;
1361
1362     /* call message filter */
1363
1364     if (COM_CurrentApt()->filter)
1365     {
1366         DWORD handlecall;
1367         INTERFACEINFO interface_info;
1368         CALLTYPE calltype;
1369
1370         interface_info.pUnk = params->iface;
1371         interface_info.iid = params->iid;
1372         interface_info.wMethod = msg->ProcNum;
1373
1374         if (IsEqualGUID(&orpcthis.cid, &COM_CurrentInfo()->causality_id))
1375             calltype = CALLTYPE_NESTED;
1376         else if (COM_CurrentInfo()->pending_call_count_server == 0)
1377             calltype = CALLTYPE_TOPLEVEL;
1378         else
1379             calltype = CALLTYPE_TOPLEVEL_CALLPENDING;
1380
1381         handlecall = IMessageFilter_HandleInComingCall(COM_CurrentApt()->filter,
1382                                                        calltype,
1383                                                        UlongToHandle(GetCurrentProcessId()),
1384                                                        0 /* FIXME */,
1385                                                        &interface_info);
1386         TRACE("IMessageFilter_HandleInComingCall returned %d\n", handlecall);
1387         switch (handlecall)
1388         {
1389         case SERVERCALL_REJECTED:
1390             params->hr = RPC_E_CALL_REJECTED;
1391             goto exit_reset_state;
1392         case SERVERCALL_RETRYLATER:
1393 #if 0 /* FIXME: handle retries on the client side before enabling this code */
1394             params->hr = RPC_E_RETRY;
1395             goto exit_reset_state;
1396 #else
1397             FIXME("retry call later not implemented\n");
1398             break;
1399 #endif
1400         case SERVERCALL_ISHANDLED:
1401         default:
1402             break;
1403         }
1404     }
1405
1406     /* invoke the method */
1407
1408     /* save the old causality ID - note: any calls executed while processing
1409      * messages received during the SendReceive will appear to originate from
1410      * this call - this should be checked with what Windows does */
1411     old_causality_id = COM_CurrentInfo()->causality_id;
1412     COM_CurrentInfo()->causality_id = orpcthis.cid;
1413     COM_CurrentInfo()->pending_call_count_server++;
1414     params->hr = IRpcStubBuffer_Invoke(params->stub, params->msg, params->chan);
1415     COM_CurrentInfo()->pending_call_count_server--;
1416     COM_CurrentInfo()->causality_id = old_causality_id;
1417
1418     /* the invoke allocated a new buffer, so free the old one */
1419     if (message_state->bypass_rpcrt && original_buffer != msg->Buffer)
1420         HeapFree(GetProcessHeap(), 0, original_buffer);
1421
1422 exit_reset_state:
1423     message_state = msg->Handle;
1424     msg->Handle = message_state->binding_handle;
1425     msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
1426     msg->BufferLength += message_state->prefix_data_len;
1427
1428 exit:
1429     HeapFree(GetProcessHeap(), 0, message_state);
1430     if (params->handle) SetEvent(params->handle);
1431 }
1432
1433 static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg)
1434 {
1435     struct dispatch_params *params;
1436     APARTMENT *apt;
1437     IPID ipid;
1438     HRESULT hr;
1439
1440     RpcBindingInqObject(msg->Handle, &ipid);
1441
1442     TRACE("ipid = %s, iMethod = %d\n", debugstr_guid(&ipid), msg->ProcNum);
1443
1444     params = HeapAlloc(GetProcessHeap(), 0, sizeof(*params));
1445     if (!params)
1446     {
1447         RpcRaiseException(E_OUTOFMEMORY);
1448         return;
1449     }
1450
1451     hr = ipid_get_dispatch_params(&ipid, &apt, &params->stub, &params->chan,
1452                                   &params->iid, &params->iface);
1453     if (hr != S_OK)
1454     {
1455         ERR("no apartment found for ipid %s\n", debugstr_guid(&ipid));
1456         HeapFree(GetProcessHeap(), 0, params);
1457         RpcRaiseException(hr);
1458         return;
1459     }
1460
1461     params->msg = (RPCOLEMESSAGE *)msg;
1462     params->status = RPC_S_OK;
1463     params->hr = S_OK;
1464     params->handle = NULL;
1465     params->bypass_rpcrt = FALSE;
1466
1467     /* Note: this is the important difference between STAs and MTAs - we
1468      * always execute RPCs to STAs in the thread that originally created the
1469      * apartment (i.e. the one that pumps messages to the window) */
1470     if (!apt->multi_threaded)
1471     {
1472         params->handle = CreateEventW(NULL, FALSE, FALSE, NULL);
1473
1474         TRACE("Calling apartment thread 0x%08x...\n", apt->tid);
1475
1476         if (PostMessageW(apartment_getwindow(apt), DM_EXECUTERPC, 0, (LPARAM)params))
1477             WaitForSingleObject(params->handle, INFINITE);
1478         else
1479         {
1480             ERR("PostMessage failed with error %u\n", GetLastError());
1481             IRpcChannelBuffer_Release(params->chan);
1482             IRpcStubBuffer_Release(params->stub);
1483         }
1484         CloseHandle(params->handle);
1485     }
1486     else
1487     {
1488         BOOL joined = FALSE;
1489         if (!COM_CurrentInfo()->apt)
1490         {
1491             apartment_joinmta();
1492             joined = TRUE;
1493         }
1494         RPC_ExecuteCall(params);
1495         if (joined)
1496         {
1497             apartment_release(COM_CurrentInfo()->apt);
1498             COM_CurrentInfo()->apt = NULL;
1499         }
1500     }
1501
1502     hr = params->hr;
1503     if (params->chan)
1504         IRpcChannelBuffer_Release(params->chan);
1505     if (params->stub)
1506         IRpcStubBuffer_Release(params->stub);
1507     HeapFree(GetProcessHeap(), 0, params);
1508
1509     apartment_release(apt);
1510
1511     /* if IRpcStubBuffer_Invoke fails, we should raise an exception to tell
1512      * the RPC runtime that the call failed */
1513     if (hr) RpcRaiseException(hr);
1514 }
1515
1516 /* stub registration */
1517 HRESULT RPC_RegisterInterface(REFIID riid)
1518 {
1519     struct registered_if *rif;
1520     BOOL found = FALSE;
1521     HRESULT hr = S_OK;
1522     
1523     TRACE("(%s)\n", debugstr_guid(riid));
1524
1525     EnterCriticalSection(&csRegIf);
1526     LIST_FOR_EACH_ENTRY(rif, &registered_interfaces, struct registered_if, entry)
1527     {
1528         if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid))
1529         {
1530             rif->refs++;
1531             found = TRUE;
1532             break;
1533         }
1534     }
1535     if (!found)
1536     {
1537         TRACE("Creating new interface\n");
1538
1539         rif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rif));
1540         if (rif)
1541         {
1542             RPC_STATUS status;
1543
1544             rif->refs = 1;
1545             rif->If.Length = sizeof(RPC_SERVER_INTERFACE);
1546             /* RPC interface ID = COM interface ID */
1547             rif->If.InterfaceId.SyntaxGUID = *riid;
1548             rif->If.DispatchTable = &rpc_dispatch;
1549             /* all other fields are 0, including the version asCOM objects
1550              * always have a version of 0.0 */
1551             status = RpcServerRegisterIfEx(
1552                 (RPC_IF_HANDLE)&rif->If,
1553                 NULL, NULL,
1554                 RPC_IF_OLE | RPC_IF_AUTOLISTEN,
1555                 RPC_C_LISTEN_MAX_CALLS_DEFAULT,
1556                 NULL);
1557             if (status == RPC_S_OK)
1558                 list_add_tail(&registered_interfaces, &rif->entry);
1559             else
1560             {
1561                 ERR("RpcServerRegisterIfEx failed with error %d\n", status);
1562                 HeapFree(GetProcessHeap(), 0, rif);
1563                 hr = HRESULT_FROM_WIN32(status);
1564             }
1565         }
1566         else
1567             hr = E_OUTOFMEMORY;
1568     }
1569     LeaveCriticalSection(&csRegIf);
1570     return hr;
1571 }
1572
1573 /* stub unregistration */
1574 void RPC_UnregisterInterface(REFIID riid)
1575 {
1576     struct registered_if *rif;
1577     EnterCriticalSection(&csRegIf);
1578     LIST_FOR_EACH_ENTRY(rif, &registered_interfaces, struct registered_if, entry)
1579     {
1580         if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid))
1581         {
1582             if (!--rif->refs)
1583             {
1584                 RpcServerUnregisterIf((RPC_IF_HANDLE)&rif->If, NULL, TRUE);
1585                 list_remove(&rif->entry);
1586                 HeapFree(GetProcessHeap(), 0, rif);
1587             }
1588             break;
1589         }
1590     }
1591     LeaveCriticalSection(&csRegIf);
1592 }
1593
1594 /* get the info for an OXID, including the IPID for the rem unknown interface
1595  * and the string binding */
1596 HRESULT RPC_ResolveOxid(OXID oxid, OXID_INFO *oxid_info)
1597 {
1598     TRACE("%s\n", wine_dbgstr_longlong(oxid));
1599
1600     oxid_info->dwTid = 0;
1601     oxid_info->dwPid = 0;
1602     oxid_info->dwAuthnHint = RPC_C_AUTHN_LEVEL_NONE;
1603     /* FIXME: this is a hack around not having an OXID resolver yet -
1604      * this function should contact the machine's OXID resolver and then it
1605      * should give us the IPID of the IRemUnknown interface */
1606     oxid_info->ipidRemUnknown.Data1 = 0xffffffff;
1607     oxid_info->ipidRemUnknown.Data2 = 0xffff;
1608     oxid_info->ipidRemUnknown.Data3 = 0xffff;
1609     memcpy(oxid_info->ipidRemUnknown.Data4, &oxid, sizeof(OXID));
1610     oxid_info->psa = NULL /* FIXME */;
1611
1612     return S_OK;
1613 }
1614
1615 /* make the apartment reachable by other threads and processes and create the
1616  * IRemUnknown object */
1617 void RPC_StartRemoting(struct apartment *apt)
1618 {
1619     if (!InterlockedExchange(&apt->remoting_started, TRUE))
1620     {
1621         WCHAR endpoint[200];
1622         RPC_STATUS status;
1623
1624         get_rpc_endpoint(endpoint, &apt->oxid);
1625     
1626         status = RpcServerUseProtseqEpW(
1627             wszRpcTransport,
1628             RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
1629             endpoint,
1630             NULL);
1631         if (status != RPC_S_OK)
1632             ERR("Couldn't register endpoint %s\n", debugstr_w(endpoint));
1633
1634         /* FIXME: move remote unknown exporting into this function */
1635     }
1636     start_apartment_remote_unknown();
1637 }
1638
1639
1640 static HRESULT create_server(REFCLSID rclsid)
1641 {
1642     static const WCHAR  wszLocalServer32[] = { 'L','o','c','a','l','S','e','r','v','e','r','3','2',0 };
1643     static const WCHAR  embedding[] = { ' ', '-','E','m','b','e','d','d','i','n','g',0 };
1644     HKEY                key;
1645     HRESULT             hres;
1646     WCHAR               command[MAX_PATH+sizeof(embedding)/sizeof(WCHAR)];
1647     DWORD               size = (MAX_PATH+1) * sizeof(WCHAR);
1648     STARTUPINFOW        sinfo;
1649     PROCESS_INFORMATION pinfo;
1650
1651     hres = COM_OpenKeyForCLSID(rclsid, wszLocalServer32, KEY_READ, &key);
1652     if (FAILED(hres)) {
1653         ERR("class %s not registered\n", debugstr_guid(rclsid));
1654         return hres;
1655     }
1656
1657     hres = RegQueryValueExW(key, NULL, NULL, NULL, (LPBYTE)command, &size);
1658     RegCloseKey(key);
1659     if (hres) {
1660         WARN("No default value for LocalServer32 key\n");
1661         return REGDB_E_CLASSNOTREG; /* FIXME: check retval */
1662     }
1663
1664     memset(&sinfo,0,sizeof(sinfo));
1665     sinfo.cb = sizeof(sinfo);
1666
1667     /* EXE servers are started with the -Embedding switch. */
1668
1669     strcatW(command, embedding);
1670
1671     TRACE("activating local server %s for %s\n", debugstr_w(command), debugstr_guid(rclsid));
1672
1673     /* FIXME: Win2003 supports a ServerExecutable value that is passed into
1674      * CreateProcess */
1675     if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo)) {
1676         WARN("failed to run local server %s\n", debugstr_w(command));
1677         return HRESULT_FROM_WIN32(GetLastError());
1678     }
1679     CloseHandle(pinfo.hProcess);
1680     CloseHandle(pinfo.hThread);
1681
1682     return S_OK;
1683 }
1684
1685 /*
1686  * start_local_service()  - start a service given its name and parameters
1687  */
1688 static DWORD start_local_service(LPCWSTR name, DWORD num, LPCWSTR *params)
1689 {
1690     SC_HANDLE handle, hsvc;
1691     DWORD     r = ERROR_FUNCTION_FAILED;
1692
1693     TRACE("Starting service %s %d params\n", debugstr_w(name), num);
1694
1695     handle = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
1696     if (!handle)
1697         return r;
1698     hsvc = OpenServiceW(handle, name, SERVICE_START);
1699     if (hsvc)
1700     {
1701         if(StartServiceW(hsvc, num, params))
1702             r = ERROR_SUCCESS;
1703         else
1704             r = GetLastError();
1705         if (r == ERROR_SERVICE_ALREADY_RUNNING)
1706             r = ERROR_SUCCESS;
1707         CloseServiceHandle(hsvc);
1708     }
1709     else
1710         r = GetLastError();
1711     CloseServiceHandle(handle);
1712
1713     TRACE("StartService returned error %u (%s)\n", r, (r == ERROR_SUCCESS) ? "ok":"failed");
1714
1715     return r;
1716 }
1717
1718 /*
1719  * create_local_service()  - start a COM server in a service
1720  *
1721  *   To start a Local Service, we read the AppID value under
1722  * the class's CLSID key, then open the HKCR\\AppId key specified
1723  * there and check for a LocalService value.
1724  *
1725  * Note:  Local Services are not supported under Windows 9x
1726  */
1727 static HRESULT create_local_service(REFCLSID rclsid)
1728 {
1729     HRESULT hres;
1730     WCHAR buf[CHARS_IN_GUID];
1731     static const WCHAR szLocalService[] = { 'L','o','c','a','l','S','e','r','v','i','c','e',0 };
1732     static const WCHAR szServiceParams[] = {'S','e','r','v','i','c','e','P','a','r','a','m','s',0};
1733     HKEY hkey;
1734     LONG r;
1735     DWORD type, sz;
1736
1737     TRACE("Attempting to start Local service for %s\n", debugstr_guid(rclsid));
1738
1739     hres = COM_OpenKeyForAppIdFromCLSID(rclsid, KEY_READ, &hkey);
1740     if (FAILED(hres))
1741         return hres;
1742
1743     /* read the LocalService and ServiceParameters values from the AppID key */
1744     sz = sizeof buf;
1745     r = RegQueryValueExW(hkey, szLocalService, NULL, &type, (LPBYTE)buf, &sz);
1746     if (r==ERROR_SUCCESS && type==REG_SZ)
1747     {
1748         DWORD num_args = 0;
1749         LPWSTR args[1] = { NULL };
1750
1751         /*
1752          * FIXME: I'm not really sure how to deal with the service parameters.
1753          *        I suspect that the string returned from RegQueryValueExW
1754          *        should be split into a number of arguments by spaces.
1755          *        It would make more sense if ServiceParams contained a
1756          *        REG_MULTI_SZ here, but it's a REG_SZ for the services
1757          *        that I'm interested in for the moment.
1758          */
1759         r = RegQueryValueExW(hkey, szServiceParams, NULL, &type, NULL, &sz);
1760         if (r == ERROR_SUCCESS && type == REG_SZ && sz)
1761         {
1762             args[0] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz);
1763             num_args++;
1764             RegQueryValueExW(hkey, szServiceParams, NULL, &type, (LPBYTE)args[0], &sz);
1765         }
1766         r = start_local_service(buf, num_args, (LPCWSTR *)args);
1767         if (r != ERROR_SUCCESS)
1768             hres = REGDB_E_CLASSNOTREG; /* FIXME: check retval */
1769         HeapFree(GetProcessHeap(),0,args[0]);
1770     }
1771     else
1772     {
1773         WARN("No LocalService value\n");
1774         hres = REGDB_E_CLASSNOTREG; /* FIXME: check retval */
1775     }
1776     RegCloseKey(hkey);
1777
1778     return hres;
1779 }
1780
1781
1782 static void get_localserver_pipe_name(WCHAR *pipefn, REFCLSID rclsid)
1783 {
1784     static const WCHAR wszPipeRef[] = {'\\','\\','.','\\','p','i','p','e','\\',0};
1785     strcpyW(pipefn, wszPipeRef);
1786     StringFromGUID2(rclsid, pipefn + sizeof(wszPipeRef)/sizeof(wszPipeRef[0]) - 1, CHARS_IN_GUID);
1787 }
1788
1789 /* FIXME: should call to rpcss instead */
1790 HRESULT RPC_GetLocalClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
1791 {
1792     HRESULT        hres;
1793     HANDLE         hPipe;
1794     WCHAR          pipefn[100];
1795     DWORD          res, bufferlen;
1796     char           marshalbuffer[200];
1797     IStream       *pStm;
1798     LARGE_INTEGER  seekto;
1799     ULARGE_INTEGER newpos;
1800     int            tries = 0;
1801
1802     static const int MAXTRIES = 30; /* 30 seconds */
1803
1804     TRACE("rclsid=%s, iid=%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1805
1806     get_localserver_pipe_name(pipefn, rclsid);
1807
1808     while (tries++ < MAXTRIES) {
1809         TRACE("waiting for %s\n", debugstr_w(pipefn));
1810
1811         WaitNamedPipeW( pipefn, NMPWAIT_WAIT_FOREVER );
1812         hPipe = CreateFileW(pipefn, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1813         if (hPipe == INVALID_HANDLE_VALUE) {
1814             DWORD index;
1815             DWORD start_ticks;
1816             if (tries == 1) {
1817                 if ( (hres = create_local_service(rclsid)) &&
1818                      (hres = create_server(rclsid)) )
1819                     return hres;
1820             } else {
1821                 WARN("Connecting to %s, no response yet, retrying: le is %u\n", debugstr_w(pipefn), GetLastError());
1822             }
1823             /* wait for one second, even if messages arrive */
1824             start_ticks = GetTickCount();
1825             do {
1826                 CoWaitForMultipleHandles(0, 1000, 0, NULL, &index);
1827             } while (GetTickCount() - start_ticks < 1000);
1828             continue;
1829         }
1830         bufferlen = 0;
1831         if (!ReadFile(hPipe,marshalbuffer,sizeof(marshalbuffer),&bufferlen,NULL)) {
1832             FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid));
1833             Sleep(1000);
1834             continue;
1835         }
1836         TRACE("read marshal id from pipe\n");
1837         CloseHandle(hPipe);
1838         break;
1839     }
1840     
1841     if (tries >= MAXTRIES)
1842         return E_NOINTERFACE;
1843     
1844     hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
1845     if (hres) return hres;
1846     hres = IStream_Write(pStm,marshalbuffer,bufferlen,&res);
1847     if (hres) goto out;
1848     seekto.u.LowPart = 0;seekto.u.HighPart = 0;
1849     hres = IStream_Seek(pStm,seekto,STREAM_SEEK_SET,&newpos);
1850     
1851     TRACE("unmarshalling classfactory\n");
1852     hres = CoUnmarshalInterface(pStm,&IID_IClassFactory,ppv);
1853 out:
1854     IStream_Release(pStm);
1855     return hres;
1856 }
1857
1858
1859 struct local_server_params
1860 {
1861     CLSID clsid;
1862     IStream *stream;
1863     HANDLE ready_event;
1864     HANDLE stop_event;
1865     HANDLE thread;
1866     BOOL multi_use;
1867 };
1868
1869 /* FIXME: should call to rpcss instead */
1870 static DWORD WINAPI local_server_thread(LPVOID param)
1871 {
1872     struct local_server_params * lsp = param;
1873     HANDLE              hPipe;
1874     WCHAR               pipefn[100];
1875     HRESULT             hres;
1876     IStream             *pStm = lsp->stream;
1877     STATSTG             ststg;
1878     unsigned char       *buffer;
1879     int                 buflen;
1880     LARGE_INTEGER       seekto;
1881     ULARGE_INTEGER      newpos;
1882     ULONG               res;
1883     BOOL multi_use = lsp->multi_use;
1884     OVERLAPPED ovl;
1885     HANDLE pipe_event;
1886     DWORD  bytes;
1887
1888     TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid));
1889
1890     memset(&ovl, 0, sizeof(ovl));
1891     get_localserver_pipe_name(pipefn, &lsp->clsid);
1892
1893     hPipe = CreateNamedPipeW( pipefn, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
1894                               PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
1895                               4096, 4096, 500 /* 0.5 second timeout */, NULL );
1896
1897     SetEvent(lsp->ready_event);
1898
1899     if (hPipe == INVALID_HANDLE_VALUE)
1900     {
1901         FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError());
1902         return 1;
1903     }
1904
1905     ovl.hEvent = pipe_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1906     
1907     while (1) {
1908         if (!ConnectNamedPipe(hPipe, &ovl))
1909         {
1910             DWORD error = GetLastError();
1911             if (error == ERROR_IO_PENDING)
1912             {
1913                 HANDLE handles[2] = { pipe_event, lsp->stop_event };
1914                 DWORD ret;
1915                 ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1916                 if (ret != WAIT_OBJECT_0)
1917                     break;
1918             }
1919             /* client already connected isn't an error */
1920             else if (error != ERROR_PIPE_CONNECTED)
1921             {
1922                 ERR("ConnectNamedPipe failed with error %d\n", GetLastError());
1923                 break;
1924             }
1925         }
1926
1927         TRACE("marshalling IClassFactory to client\n");
1928         
1929         hres = IStream_Stat(pStm,&ststg,STATFLAG_NONAME);
1930         if (hres) return hres;
1931
1932         seekto.u.LowPart = 0;
1933         seekto.u.HighPart = 0;
1934         hres = IStream_Seek(pStm,seekto,STREAM_SEEK_SET,&newpos);
1935         if (hres) {
1936             FIXME("IStream_Seek failed, %x\n",hres);
1937             CloseHandle(hPipe);
1938             CloseHandle(pipe_event);
1939             return hres;
1940         }
1941
1942         buflen = ststg.cbSize.u.LowPart;
1943         buffer = HeapAlloc(GetProcessHeap(),0,buflen);
1944         
1945         hres = IStream_Read(pStm,buffer,buflen,&res);
1946         if (hres) {
1947             FIXME("Stream Read failed, %x\n",hres);
1948             CloseHandle(hPipe);
1949             CloseHandle(pipe_event);
1950             HeapFree(GetProcessHeap(),0,buffer);
1951             return hres;
1952         }
1953         
1954         WriteFile(hPipe,buffer,buflen,&res,&ovl);
1955         GetOverlappedResult(hPipe, &ovl, &bytes, TRUE);
1956         HeapFree(GetProcessHeap(),0,buffer);
1957
1958         FlushFileBuffers(hPipe);
1959         DisconnectNamedPipe(hPipe);
1960
1961         TRACE("done marshalling IClassFactory\n");
1962
1963         if (!multi_use)
1964         {
1965             TRACE("single use object, shutting down pipe %s\n", debugstr_w(pipefn));
1966             break;
1967         }
1968     }
1969     CloseHandle(hPipe);
1970     CloseHandle(pipe_event);
1971     return 0;
1972 }
1973
1974 /* starts listening for a local server */
1975 HRESULT RPC_StartLocalServer(REFCLSID clsid, IStream *stream, BOOL multi_use, void **registration)
1976 {
1977     DWORD tid;
1978     struct local_server_params *lsp;
1979
1980     lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp));
1981     if (!lsp)
1982         return E_OUTOFMEMORY;
1983
1984     lsp->clsid = *clsid;
1985     lsp->stream = stream;
1986     IStream_AddRef(stream);
1987     lsp->ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1988     if (!lsp->ready_event)
1989     {
1990         HeapFree(GetProcessHeap(), 0, lsp);
1991         return HRESULT_FROM_WIN32(GetLastError());
1992     }
1993     lsp->stop_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1994     if (!lsp->stop_event)
1995     {
1996         CloseHandle(lsp->ready_event);
1997         HeapFree(GetProcessHeap(), 0, lsp);
1998         return HRESULT_FROM_WIN32(GetLastError());
1999     }
2000     lsp->multi_use = multi_use;
2001
2002     lsp->thread = CreateThread(NULL, 0, local_server_thread, lsp, 0, &tid);
2003     if (!lsp->thread)
2004     {
2005         CloseHandle(lsp->ready_event);
2006         CloseHandle(lsp->stop_event);
2007         HeapFree(GetProcessHeap(), 0, lsp);
2008         return HRESULT_FROM_WIN32(GetLastError());
2009     }
2010
2011     WaitForSingleObject(lsp->ready_event, INFINITE);
2012     CloseHandle(lsp->ready_event);
2013     lsp->ready_event = NULL;
2014
2015     *registration = lsp;
2016     return S_OK;
2017 }
2018
2019 /* stops listening for a local server */
2020 void RPC_StopLocalServer(void *registration)
2021 {
2022     struct local_server_params *lsp = registration;
2023
2024     /* signal local_server_thread to stop */
2025     SetEvent(lsp->stop_event);
2026     /* wait for it to exit */
2027     WaitForSingleObject(lsp->thread, INFINITE);
2028
2029     IStream_Release(lsp->stream);
2030     CloseHandle(lsp->stop_event);
2031     CloseHandle(lsp->thread);
2032     HeapFree(GetProcessHeap(), 0, lsp);
2033 }