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