4 * Copyright 2001 Ove Kåven, TransGaming Technologies
5 * Copyright 2002 Marcus Meissner
6 * Copyright 2005 Mike Hearn, Rob Shearman for CodeWeavers
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.
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.
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
24 #include "wine/port.h"
33 #define NONAMELESSUNION
34 #define NONAMELESSSTRUCT
46 #include "wine/unicode.h"
48 #include "compobj_private.h"
50 #include "wine/debug.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(ole);
54 static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg);
56 /* we only use one function to dispatch calls for all methods - we use the
57 * RPC_IF_OLE flag to tell the RPC runtime that this is the case */
58 static RPC_DISPATCH_FUNCTION rpc_dispatch_table[1] = { dispatch_rpc }; /* (RO) */
59 static RPC_DISPATCH_TABLE rpc_dispatch = { 1, rpc_dispatch_table }; /* (RO) */
61 static struct list registered_interfaces = LIST_INIT(registered_interfaces); /* (CS csRegIf) */
62 static CRITICAL_SECTION csRegIf;
63 static CRITICAL_SECTION_DEBUG csRegIf_debug =
66 { &csRegIf_debug.ProcessLocksList, &csRegIf_debug.ProcessLocksList },
67 0, 0, { (DWORD_PTR)(__FILE__ ": dcom registered server interfaces") }
69 static CRITICAL_SECTION csRegIf = { &csRegIf_debug, -1, 0, 0, 0, 0 };
71 static struct list channel_hooks = LIST_INIT(channel_hooks); /* (CS csChannelHook) */
72 static CRITICAL_SECTION csChannelHook;
73 static CRITICAL_SECTION_DEBUG csChannelHook_debug =
76 { &csChannelHook_debug.ProcessLocksList, &csChannelHook_debug.ProcessLocksList },
77 0, 0, { (DWORD_PTR)(__FILE__ ": channel hooks") }
79 static CRITICAL_SECTION csChannelHook = { &csChannelHook_debug, -1, 0, 0, 0, 0 };
81 static WCHAR wszRpcTransport[] = {'n','c','a','l','r','p','c',0};
87 DWORD refs; /* ref count */
88 RPC_SERVER_INTERFACE If; /* interface registered with the RPC runtime */
91 /* get the pipe endpoint specified of the specified apartment */
92 static inline void get_rpc_endpoint(LPWSTR endpoint, const OXID *oxid)
94 /* FIXME: should get endpoint from rpcss */
95 static const WCHAR wszEndpointFormat[] = {'\\','p','i','p','e','\\','O','L','E','_','%','0','8','l','x','%','0','8','l','x',0};
96 wsprintfW(endpoint, wszEndpointFormat, (DWORD)(*oxid >> 32),(DWORD)*oxid);
101 const IRpcChannelBufferVtbl *lpVtbl;
107 RpcChannelBuffer super; /* superclass */
109 RPC_BINDING_HANDLE bind; /* handle to the remote server */
110 OXID oxid; /* apartment in which the channel is valid */
111 DWORD dest_context; /* returned from GetDestCtx */
112 LPVOID dest_context_data; /* returned from GetDestCtx */
113 HANDLE event; /* cached event handle */
114 } ClientRpcChannelBuffer;
116 struct dispatch_params
118 RPCOLEMESSAGE *msg; /* message */
119 IRpcStubBuffer *stub; /* stub buffer, if applicable */
120 IRpcChannelBuffer *chan; /* server channel buffer, if applicable */
121 HANDLE handle; /* handle that will become signaled when call finishes */
122 RPC_STATUS status; /* status (out) */
123 HRESULT hr; /* hresult (out) */
128 RPC_BINDING_HANDLE binding_handle;
129 ULONG prefix_data_len;
130 SChannelHookCallInfo channel_hook_info;
135 ULONG conformance; /* NDR */
138 /* [size_is((size+7)&~7)] */ unsigned char data[1];
141 struct channel_hook_entry
148 struct channel_hook_buffer_data
151 ULONG extension_size;
155 /* Channel Hook Functions */
157 static ULONG ChannelHooks_ClientGetSize(SChannelHookCallInfo *info,
158 struct channel_hook_buffer_data **data, unsigned int *hook_count,
159 ULONG *extension_count)
161 struct channel_hook_entry *entry;
162 ULONG total_size = 0;
163 unsigned int hook_index = 0;
166 *extension_count = 0;
168 EnterCriticalSection(&csChannelHook);
170 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
174 *data = HeapAlloc(GetProcessHeap(), 0, *hook_count * sizeof(struct channel_hook_buffer_data));
178 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
180 ULONG extension_size = 0;
182 IChannelHook_ClientGetSize(entry->hook, &entry->id, &info->iid, &extension_size);
184 TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size);
186 extension_size = (extension_size+7)&~7;
187 (*data)[hook_index].id = entry->id;
188 (*data)[hook_index].extension_size = extension_size;
190 /* an extension is only put onto the wire if it has data to write */
193 total_size += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[extension_size]);
194 (*extension_count)++;
200 LeaveCriticalSection(&csChannelHook);
205 static unsigned char * ChannelHooks_ClientFillBuffer(SChannelHookCallInfo *info,
206 unsigned char *buffer, struct channel_hook_buffer_data *data,
207 unsigned int hook_count)
209 struct channel_hook_entry *entry;
211 EnterCriticalSection(&csChannelHook);
213 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
216 ULONG extension_size = 0;
217 WIRE_ORPC_EXTENT *wire_orpc_extent = (WIRE_ORPC_EXTENT *)buffer;
219 for (i = 0; i < hook_count; i++)
220 if (IsEqualGUID(&entry->id, &data[i].id))
221 extension_size = data[i].extension_size;
223 /* an extension is only put onto the wire if it has data to write */
227 IChannelHook_ClientFillBuffer(entry->hook, &entry->id, &info->iid,
228 &extension_size, buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]));
230 TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size);
232 /* FIXME: set unused portion of wire_orpc_extent->data to 0? */
234 wire_orpc_extent->conformance = (extension_size+7)&~7;
235 wire_orpc_extent->size = extension_size;
236 memcpy(&wire_orpc_extent->id, &entry->id, sizeof(wire_orpc_extent->id));
237 buffer += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[wire_orpc_extent->conformance]);
240 LeaveCriticalSection(&csChannelHook);
242 HeapFree(GetProcessHeap(), 0, data);
247 static void ChannelHooks_ServerNotify(SChannelHookCallInfo *info,
248 DWORD lDataRep, WIRE_ORPC_EXTENT *first_wire_orpc_extent,
249 ULONG extension_count)
251 struct channel_hook_entry *entry;
254 EnterCriticalSection(&csChannelHook);
256 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
258 WIRE_ORPC_EXTENT *wire_orpc_extent;
259 for (i = 0, wire_orpc_extent = first_wire_orpc_extent;
261 i++, wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance])
263 if (IsEqualGUID(&entry->id, &wire_orpc_extent->id))
266 if (i == extension_count) wire_orpc_extent = NULL;
268 IChannelHook_ServerNotify(entry->hook, &entry->id, &info->iid,
269 wire_orpc_extent ? wire_orpc_extent->size : 0,
270 wire_orpc_extent ? wire_orpc_extent->data : NULL,
274 LeaveCriticalSection(&csChannelHook);
277 HRESULT RPC_RegisterChannelHook(REFGUID rguid, IChannelHook *hook)
279 struct channel_hook_entry *entry;
281 TRACE("(%s, %p)\n", debugstr_guid(rguid), hook);
283 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
285 return E_OUTOFMEMORY;
287 memcpy(&entry->id, rguid, sizeof(entry->id));
289 IChannelHook_AddRef(hook);
291 EnterCriticalSection(&csChannelHook);
292 list_add_tail(&channel_hooks, &entry->entry);
293 LeaveCriticalSection(&csChannelHook);
298 void RPC_UnregisterAllChannelHooks(void)
300 struct channel_hook_entry *cursor;
301 struct channel_hook_entry *cursor2;
303 EnterCriticalSection(&csChannelHook);
304 LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &channel_hooks, struct channel_hook_entry, entry)
305 HeapFree(GetProcessHeap(), 0, cursor);
306 LeaveCriticalSection(&csChannelHook);
309 /* RPC Channel Buffer Functions */
311 static HRESULT WINAPI RpcChannelBuffer_QueryInterface(LPRPCCHANNELBUFFER iface, REFIID riid, LPVOID *ppv)
314 if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown))
316 *ppv = (LPVOID)iface;
317 IUnknown_AddRef(iface);
320 return E_NOINTERFACE;
323 static ULONG WINAPI RpcChannelBuffer_AddRef(LPRPCCHANNELBUFFER iface)
325 RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
326 return InterlockedIncrement(&This->refs);
329 static ULONG WINAPI ServerRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface)
331 RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
334 ref = InterlockedDecrement(&This->refs);
338 HeapFree(GetProcessHeap(), 0, This);
342 static ULONG WINAPI ClientRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface)
344 ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
347 ref = InterlockedDecrement(&This->super.refs);
351 if (This->event) CloseHandle(This->event);
352 RpcBindingFree(&This->bind);
353 HeapFree(GetProcessHeap(), 0, This);
357 static HRESULT WINAPI ServerRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
359 RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
360 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
362 struct message_state *message_state;
364 TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid));
366 message_state = (struct message_state *)msg->Handle;
367 /* restore the binding handle and the real start of data */
368 msg->Handle = message_state->binding_handle;
369 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
371 status = I_RpcGetBuffer(msg);
373 /* save away the message state again */
374 msg->Handle = message_state;
375 message_state->prefix_data_len = 0;
377 TRACE("-- %ld\n", status);
379 return HRESULT_FROM_WIN32(status);
382 static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
384 ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
385 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
386 RPC_CLIENT_INTERFACE *cif;
389 struct message_state *message_state;
390 ULONG extensions_size;
391 struct channel_hook_buffer_data *channel_hook_data;
392 unsigned int channel_hook_count;
393 ULONG extension_count;
395 TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid));
397 cif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_CLIENT_INTERFACE));
399 return E_OUTOFMEMORY;
401 message_state = HeapAlloc(GetProcessHeap(), 0, sizeof(*message_state));
404 HeapFree(GetProcessHeap(), 0, cif);
405 return E_OUTOFMEMORY;
408 cif->Length = sizeof(RPC_CLIENT_INTERFACE);
409 /* RPC interface ID = COM interface ID */
410 cif->InterfaceId.SyntaxGUID = *riid;
411 /* COM objects always have a version of 0.0 */
412 cif->InterfaceId.SyntaxVersion.MajorVersion = 0;
413 cif->InterfaceId.SyntaxVersion.MinorVersion = 0;
414 msg->Handle = This->bind;
415 msg->RpcInterfaceInformation = cif;
417 message_state->channel_hook_info.iid = *riid;
418 message_state->channel_hook_info.cbSize = sizeof(message_state->channel_hook_info);
419 message_state->channel_hook_info.uCausality = GUID_NULL; /* FIXME */
420 message_state->channel_hook_info.dwServerPid = 0; /* FIXME */
421 message_state->channel_hook_info.iMethod = msg->ProcNum;
422 message_state->channel_hook_info.pObject = NULL; /* only present on server-side */
424 extensions_size = ChannelHooks_ClientGetSize(&message_state->channel_hook_info,
425 &channel_hook_data, &channel_hook_count, &extension_count);
427 msg->BufferLength += FIELD_OFFSET(ORPCTHIS, extensions) + 4;
430 msg->BufferLength += FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent) + 2*sizeof(DWORD) + extensions_size;
431 if (extension_count & 1)
432 msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
435 status = I_RpcGetBuffer(msg);
437 message_state->prefix_data_len = 0;
438 message_state->binding_handle = This->bind;
439 msg->Handle = message_state;
441 if (status == RPC_S_OK)
443 orpcthis = (ORPCTHIS *)msg->Buffer;
444 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPCTHIS, extensions);
446 orpcthis->version.MajorVersion = COM_MAJOR_VERSION;
447 orpcthis->version.MinorVersion = COM_MINOR_VERSION;
448 orpcthis->flags = message_state->channel_hook_info.dwServerPid ? ORPCF_LOCAL : ORPCF_NULL;
449 orpcthis->reserved1 = 0;
450 orpcthis->cid = message_state->channel_hook_info.uCausality;
452 /* NDR representation of orpcthis->extensions */
453 *(DWORD *)msg->Buffer = extensions_size ? 1 : 0;
454 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
458 ORPC_EXTENT_ARRAY *orpc_extent_array = msg->Buffer;
459 orpc_extent_array->size = extension_count;
460 orpc_extent_array->reserved = 0;
461 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent);
462 /* NDR representation of orpc_extent_array->extent */
463 *(DWORD *)msg->Buffer = 1;
464 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
465 /* NDR representation of [size_is] attribute of orpc_extent_array->extent */
466 *(DWORD *)msg->Buffer = (extension_count + 1) & ~1;
467 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
469 msg->Buffer = ChannelHooks_ClientFillBuffer(&message_state->channel_hook_info,
470 msg->Buffer, channel_hook_data, channel_hook_count);
472 /* we must add a dummy extension if there is an odd extension
473 * count to meet the contract specified by the size_is attribute */
474 if (extension_count & 1)
476 WIRE_ORPC_EXTENT *wire_orpc_extent = msg->Buffer;
477 wire_orpc_extent->conformance = 0;
478 memcpy(&wire_orpc_extent->id, &GUID_NULL, sizeof(wire_orpc_extent->id));
479 wire_orpc_extent->size = 0;
480 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
484 /* store the prefixed data length so that we can restore the real buffer
485 * pointer in ClientRpcChannelBuffer_SendReceive. */
486 message_state->prefix_data_len = (char *)msg->Buffer - (char *)orpcthis;
487 msg->BufferLength -= message_state->prefix_data_len;
490 TRACE("-- %ld\n", status);
492 return HRESULT_FROM_WIN32(status);
495 static HRESULT WINAPI ServerRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus)
501 static HANDLE ClientRpcChannelBuffer_GetEventHandle(ClientRpcChannelBuffer *This)
503 HANDLE event = InterlockedExchangePointer(&This->event, NULL);
505 /* Note: must be auto-reset event so we can reuse it without a call
507 if (!event) event = CreateEventW(NULL, FALSE, FALSE, NULL);
512 static void ClientRpcChannelBuffer_ReleaseEventHandle(ClientRpcChannelBuffer *This, HANDLE event)
514 if (InterlockedCompareExchangePointer(&This->event, event, NULL))
515 /* already a handle cached in This */
519 /* this thread runs an outgoing RPC */
520 static DWORD WINAPI rpc_sendreceive_thread(LPVOID param)
522 struct dispatch_params *data = (struct dispatch_params *) param;
524 /* FIXME: trap and rethrow RPC exceptions in app thread */
525 data->status = I_RpcSendReceive((RPC_MESSAGE *)data->msg);
527 TRACE("completed with status 0x%lx\n", data->status);
529 SetEvent(data->handle);
534 static inline HRESULT ClientRpcChannelBuffer_IsCorrectApartment(ClientRpcChannelBuffer *This, APARTMENT *apt)
539 if (apartment_getoxid(apt, &oxid) != S_OK)
541 if (This->oxid != oxid)
546 static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus)
548 ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
550 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
553 struct dispatch_params *params;
554 APARTMENT *apt = NULL;
556 struct message_state *message_state;
558 TRACE("(%p) iMethod=%d\n", olemsg, olemsg->iMethod);
560 hr = ClientRpcChannelBuffer_IsCorrectApartment(This, COM_CurrentApt());
563 ERR("called from wrong apartment, should have been 0x%s\n",
564 wine_dbgstr_longlong(This->oxid));
565 return RPC_E_WRONG_THREAD;
568 params = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*params));
569 if (!params) return E_OUTOFMEMORY;
571 message_state = (struct message_state *)msg->Handle;
572 /* restore the binding handle and the real start of data */
573 msg->Handle = message_state->binding_handle;
574 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
575 msg->BufferLength += message_state->prefix_data_len;
577 params->msg = olemsg;
578 params->status = RPC_S_OK;
581 /* Note: this is an optimization in the Microsoft OLE runtime that we need
582 * to copy, as shown by the test_no_couninitialize_client test. without
583 * short-circuiting the RPC runtime in the case below, the test will
584 * deadlock on the loader lock due to the RPC runtime needing to create
585 * a thread to process the RPC when this function is called indirectly
588 RpcBindingInqObject(message_state->binding_handle, &ipid);
589 hr = ipid_get_dispatch_params(&ipid, &apt, ¶ms->stub, ¶ms->chan);
590 params->handle = ClientRpcChannelBuffer_GetEventHandle(This);
591 if ((hr == S_OK) && !apt->multi_threaded)
593 TRACE("Calling apartment thread 0x%08x...\n", apt->tid);
595 if (!PostMessageW(apartment_getwindow(apt), DM_EXECUTERPC, 0, (LPARAM)params))
597 ERR("PostMessage failed with error %d\n", GetLastError());
598 hr = HRESULT_FROM_WIN32(GetLastError());
605 /* otherwise, we go via RPC runtime so the stub and channel aren't
607 IRpcStubBuffer_Release(params->stub);
609 IRpcChannelBuffer_Release(params->chan);
613 /* we use a separate thread here because we need to be able to
614 * pump the message loop in the application thread: if we do not,
615 * any windows created by this thread will hang and RPCs that try
616 * and re-enter this STA from an incoming server thread will
617 * deadlock. InstallShield is an example of that.
619 if (!QueueUserWorkItem(rpc_sendreceive_thread, params, WT_EXECUTEDEFAULT))
621 ERR("QueueUserWorkItem failed with error %x\n", GetLastError());
627 if (apt) apartment_release(apt);
631 if (WaitForSingleObject(params->handle, 0))
632 hr = CoWaitForMultipleHandles(0, INFINITE, 1, ¶ms->handle, &index);
634 ClientRpcChannelBuffer_ReleaseEventHandle(This, params->handle);
636 /* save away the message state again */
637 msg->Handle = message_state;
638 message_state->prefix_data_len = 0;
640 if (hr == S_OK) hr = params->hr;
642 status = params->status;
643 HeapFree(GetProcessHeap(), 0, params);
648 if (pstatus) *pstatus = status;
650 TRACE("RPC call status: 0x%lx\n", status);
651 if (status == RPC_S_OK)
653 else if (status == RPC_S_CALL_FAILED)
654 hr = *(HRESULT *)olemsg->Buffer;
656 hr = HRESULT_FROM_WIN32(status);
658 TRACE("-- 0x%08x\n", hr);
663 static HRESULT WINAPI ServerRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
665 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
667 struct message_state *message_state;
669 TRACE("(%p)\n", msg);
671 message_state = (struct message_state *)msg->Handle;
672 /* restore the binding handle and the real start of data */
673 msg->Handle = message_state->binding_handle;
674 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
675 msg->BufferLength += message_state->prefix_data_len;
676 message_state->prefix_data_len = 0;
678 status = I_RpcFreeBuffer(msg);
680 msg->Handle = message_state;
682 TRACE("-- %ld\n", status);
684 return HRESULT_FROM_WIN32(status);
687 static HRESULT WINAPI ClientRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
689 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
691 struct message_state *message_state;
693 TRACE("(%p)\n", msg);
695 message_state = (struct message_state *)msg->Handle;
696 /* restore the binding handle and the real start of data */
697 msg->Handle = message_state->binding_handle;
698 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
699 msg->BufferLength += message_state->prefix_data_len;
701 status = I_RpcFreeBuffer(msg);
703 HeapFree(GetProcessHeap(), 0, msg->RpcInterfaceInformation);
704 msg->RpcInterfaceInformation = NULL;
705 HeapFree(GetProcessHeap(), 0, message_state);
707 TRACE("-- %ld\n", status);
709 return HRESULT_FROM_WIN32(status);
712 static HRESULT WINAPI ClientRpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext)
714 ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
716 TRACE("(%p,%p)\n", pdwDestContext, ppvDestContext);
718 *pdwDestContext = This->dest_context;
719 *ppvDestContext = This->dest_context_data;
724 static HRESULT WINAPI ServerRpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext)
726 FIXME("(%p,%p), stub!\n", pdwDestContext, ppvDestContext);
730 static HRESULT WINAPI RpcChannelBuffer_IsConnected(LPRPCCHANNELBUFFER iface)
733 /* native does nothing too */
737 static const IRpcChannelBufferVtbl ClientRpcChannelBufferVtbl =
739 RpcChannelBuffer_QueryInterface,
740 RpcChannelBuffer_AddRef,
741 ClientRpcChannelBuffer_Release,
742 ClientRpcChannelBuffer_GetBuffer,
743 ClientRpcChannelBuffer_SendReceive,
744 ClientRpcChannelBuffer_FreeBuffer,
745 ClientRpcChannelBuffer_GetDestCtx,
746 RpcChannelBuffer_IsConnected
749 static const IRpcChannelBufferVtbl ServerRpcChannelBufferVtbl =
751 RpcChannelBuffer_QueryInterface,
752 RpcChannelBuffer_AddRef,
753 ServerRpcChannelBuffer_Release,
754 ServerRpcChannelBuffer_GetBuffer,
755 ServerRpcChannelBuffer_SendReceive,
756 ServerRpcChannelBuffer_FreeBuffer,
757 ServerRpcChannelBuffer_GetDestCtx,
758 RpcChannelBuffer_IsConnected
761 /* returns a channel buffer for proxies */
762 HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid,
763 DWORD dest_context, void *dest_context_data,
764 IRpcChannelBuffer **chan)
766 ClientRpcChannelBuffer *This;
768 RPC_BINDING_HANDLE bind;
770 LPWSTR string_binding;
772 /* connect to the apartment listener thread */
773 get_rpc_endpoint(endpoint, oxid);
775 TRACE("proxy pipe: connecting to endpoint: %s\n", debugstr_w(endpoint));
777 status = RpcStringBindingComposeW(
785 if (status == RPC_S_OK)
787 status = RpcBindingFromStringBindingW(string_binding, &bind);
789 if (status == RPC_S_OK)
791 IPID ipid2 = *ipid; /* why can't RpcBindingSetObject take a const? */
792 status = RpcBindingSetObject(bind, &ipid2);
793 if (status != RPC_S_OK)
794 RpcBindingFree(&bind);
797 RpcStringFreeW(&string_binding);
800 if (status != RPC_S_OK)
802 ERR("Couldn't get binding for endpoint %s, status = %ld\n", debugstr_w(endpoint), status);
803 return HRESULT_FROM_WIN32(status);
806 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
809 RpcBindingFree(&bind);
810 return E_OUTOFMEMORY;
813 This->super.lpVtbl = &ClientRpcChannelBufferVtbl;
814 This->super.refs = 1;
816 apartment_getoxid(COM_CurrentApt(), &This->oxid);
817 This->dest_context = dest_context;
818 This->dest_context_data = dest_context_data;
821 *chan = (IRpcChannelBuffer*)This;
826 HRESULT RPC_CreateServerChannel(IRpcChannelBuffer **chan)
828 RpcChannelBuffer *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
830 return E_OUTOFMEMORY;
832 This->lpVtbl = &ServerRpcChannelBufferVtbl;
835 *chan = (IRpcChannelBuffer*)This;
840 /* unmarshals ORPCTHIS according to NDR rules, but doesn't allocate any memory */
841 static HRESULT unmarshal_ORPCTHIS(RPC_MESSAGE *msg, ORPCTHIS *orpcthis,
842 ORPC_EXTENT_ARRAY *orpc_ext_array, WIRE_ORPC_EXTENT **first_wire_orpc_extent)
844 const char *end = (char *)msg->Buffer + msg->BufferLength;
846 *first_wire_orpc_extent = NULL;
848 if (msg->BufferLength < FIELD_OFFSET(ORPCTHIS, extensions) + 4)
850 ERR("invalid buffer length\n");
851 return RPC_E_INVALID_HEADER;
854 memcpy(orpcthis, msg->Buffer, FIELD_OFFSET(ORPCTHIS, extensions));
855 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPCTHIS, extensions);
857 if ((const char *)msg->Buffer + sizeof(DWORD) > end)
858 return RPC_E_INVALID_HEADER;
860 if (*(DWORD *)msg->Buffer)
861 orpcthis->extensions = orpc_ext_array;
863 orpcthis->extensions = NULL;
865 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
867 if (orpcthis->extensions)
872 memcpy(orpcthis->extensions, msg->Buffer, FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent));
873 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent);
875 if ((const char *)msg->Buffer + 2 * sizeof(DWORD) > end)
876 return RPC_E_INVALID_HEADER;
878 pointer_id = *(DWORD *)msg->Buffer;
879 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
880 orpcthis->extensions->extent = NULL;
884 WIRE_ORPC_EXTENT *wire_orpc_extent;
887 if (*(DWORD *)msg->Buffer != ((orpcthis->extensions->size+1)&~1))
888 return RPC_S_INVALID_BOUND;
890 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
892 /* arbritary limit for security (don't know what native does) */
893 if (orpcthis->extensions->size > 256)
895 ERR("too many extensions: %ld\n", orpcthis->extensions->size);
896 return RPC_S_INVALID_BOUND;
899 *first_wire_orpc_extent = wire_orpc_extent = (WIRE_ORPC_EXTENT *)msg->Buffer;
900 for (i = 0; i < ((orpcthis->extensions->size+1)&~1); i++)
902 if ((const char *)&wire_orpc_extent->data[0] > end)
903 return RPC_S_INVALID_BOUND;
904 if (wire_orpc_extent->conformance != ((wire_orpc_extent->size+7)&~7))
905 return RPC_S_INVALID_BOUND;
906 if ((const char *)&wire_orpc_extent->data[wire_orpc_extent->conformance] > end)
907 return RPC_S_INVALID_BOUND;
908 TRACE("size %u, guid %s\n", wire_orpc_extent->size, debugstr_guid(&wire_orpc_extent->id));
909 wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance];
911 msg->Buffer = wire_orpc_extent;
915 if ((orpcthis->version.MajorVersion != COM_MAJOR_VERSION) ||
916 (orpcthis->version.MinorVersion > COM_MINOR_VERSION))
918 ERR("COM version {%d, %d} not supported\n",
919 orpcthis->version.MajorVersion, orpcthis->version.MinorVersion);
920 return RPC_E_VERSION_MISMATCH;
923 if (orpcthis->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4))
925 ERR("invalid flags 0x%lx\n", orpcthis->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4));
926 return RPC_E_INVALID_HEADER;
932 void RPC_ExecuteCall(struct dispatch_params *params)
934 struct message_state *message_state;
935 RPC_MESSAGE *msg = (RPC_MESSAGE *)params->msg;
936 char *original_buffer = msg->Buffer;
938 ORPC_EXTENT_ARRAY orpc_ext_array;
939 WIRE_ORPC_EXTENT *first_wire_orpc_extent;
941 params->hr = unmarshal_ORPCTHIS(msg, &orpcthis, &orpc_ext_array, &first_wire_orpc_extent);
942 if (params->hr != S_OK)
945 message_state = HeapAlloc(GetProcessHeap(), 0, sizeof(*message_state));
948 params->hr = E_OUTOFMEMORY;
952 message_state->prefix_data_len = original_buffer - (char *)msg->Buffer;
953 message_state->binding_handle = msg->Handle;
955 message_state->channel_hook_info.iid = IID_NULL; /* FIXME */
956 message_state->channel_hook_info.cbSize = sizeof(message_state->channel_hook_info);
957 message_state->channel_hook_info.uCausality = orpcthis.cid;
958 message_state->channel_hook_info.dwServerPid = GetCurrentProcessId();
959 message_state->channel_hook_info.iMethod = msg->ProcNum;
960 message_state->channel_hook_info.pObject = NULL; /* FIXME */
962 if (orpcthis.extensions && first_wire_orpc_extent &&
963 orpcthis.extensions->size)
964 ChannelHooks_ServerNotify(&message_state->channel_hook_info, msg->DataRepresentation, first_wire_orpc_extent, orpcthis.extensions->size);
966 msg->Handle = message_state;
967 msg->BufferLength -= message_state->prefix_data_len;
969 /* invoke the method */
971 params->hr = IRpcStubBuffer_Invoke(params->stub, params->msg, params->chan);
973 message_state = (struct message_state *)msg->Handle;
974 msg->Handle = message_state->binding_handle;
975 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
976 msg->BufferLength += message_state->prefix_data_len;
977 HeapFree(GetProcessHeap(), 0, message_state);
980 IRpcStubBuffer_Release(params->stub);
981 IRpcChannelBuffer_Release(params->chan);
982 if (params->handle) SetEvent(params->handle);
985 static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg)
987 struct dispatch_params *params;
992 RpcBindingInqObject(msg->Handle, &ipid);
994 TRACE("ipid = %s, iMethod = %d\n", debugstr_guid(&ipid), msg->ProcNum);
996 params = HeapAlloc(GetProcessHeap(), 0, sizeof(*params));
997 if (!params) return RpcRaiseException(E_OUTOFMEMORY);
999 hr = ipid_get_dispatch_params(&ipid, &apt, ¶ms->stub, ¶ms->chan);
1002 ERR("no apartment found for ipid %s\n", debugstr_guid(&ipid));
1003 HeapFree(GetProcessHeap(), 0, params);
1004 return RpcRaiseException(hr);
1007 params->msg = (RPCOLEMESSAGE *)msg;
1008 params->status = RPC_S_OK;
1010 params->handle = NULL;
1012 /* Note: this is the important difference between STAs and MTAs - we
1013 * always execute RPCs to STAs in the thread that originally created the
1014 * apartment (i.e. the one that pumps messages to the window) */
1015 if (!apt->multi_threaded)
1017 params->handle = CreateEventW(NULL, FALSE, FALSE, NULL);
1019 TRACE("Calling apartment thread 0x%08x...\n", apt->tid);
1021 if (PostMessageW(apartment_getwindow(apt), DM_EXECUTERPC, 0, (LPARAM)params))
1022 WaitForSingleObject(params->handle, INFINITE);
1025 ERR("PostMessage failed with error %d\n", GetLastError());
1026 IRpcChannelBuffer_Release(params->chan);
1027 IRpcStubBuffer_Release(params->stub);
1029 CloseHandle(params->handle);
1033 BOOL joined = FALSE;
1034 if (!COM_CurrentInfo()->apt)
1036 apartment_joinmta();
1039 RPC_ExecuteCall(params);
1042 apartment_release(COM_CurrentInfo()->apt);
1043 COM_CurrentInfo()->apt = NULL;
1048 HeapFree(GetProcessHeap(), 0, params);
1050 apartment_release(apt);
1052 /* if IRpcStubBuffer_Invoke fails, we should raise an exception to tell
1053 * the RPC runtime that the call failed */
1054 if (hr) RpcRaiseException(hr);
1057 /* stub registration */
1058 HRESULT RPC_RegisterInterface(REFIID riid)
1060 struct registered_if *rif;
1064 TRACE("(%s)\n", debugstr_guid(riid));
1066 EnterCriticalSection(&csRegIf);
1067 LIST_FOR_EACH_ENTRY(rif, ®istered_interfaces, struct registered_if, entry)
1069 if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid))
1078 TRACE("Creating new interface\n");
1080 rif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rif));
1086 rif->If.Length = sizeof(RPC_SERVER_INTERFACE);
1087 /* RPC interface ID = COM interface ID */
1088 rif->If.InterfaceId.SyntaxGUID = *riid;
1089 rif->If.DispatchTable = &rpc_dispatch;
1090 /* all other fields are 0, including the version asCOM objects
1091 * always have a version of 0.0 */
1092 status = RpcServerRegisterIfEx(
1093 (RPC_IF_HANDLE)&rif->If,
1095 RPC_IF_OLE | RPC_IF_AUTOLISTEN,
1096 RPC_C_LISTEN_MAX_CALLS_DEFAULT,
1098 if (status == RPC_S_OK)
1099 list_add_tail(®istered_interfaces, &rif->entry);
1102 ERR("RpcServerRegisterIfEx failed with error %ld\n", status);
1103 HeapFree(GetProcessHeap(), 0, rif);
1104 hr = HRESULT_FROM_WIN32(status);
1110 LeaveCriticalSection(&csRegIf);
1114 /* stub unregistration */
1115 void RPC_UnregisterInterface(REFIID riid)
1117 struct registered_if *rif;
1118 EnterCriticalSection(&csRegIf);
1119 LIST_FOR_EACH_ENTRY(rif, ®istered_interfaces, struct registered_if, entry)
1121 if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid))
1125 RpcServerUnregisterIf((RPC_IF_HANDLE)&rif->If, NULL, TRUE);
1126 list_remove(&rif->entry);
1127 HeapFree(GetProcessHeap(), 0, rif);
1132 LeaveCriticalSection(&csRegIf);
1135 /* make the apartment reachable by other threads and processes and create the
1136 * IRemUnknown object */
1137 void RPC_StartRemoting(struct apartment *apt)
1139 if (!InterlockedExchange(&apt->remoting_started, TRUE))
1141 WCHAR endpoint[200];
1144 get_rpc_endpoint(endpoint, &apt->oxid);
1146 status = RpcServerUseProtseqEpW(
1148 RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
1151 if (status != RPC_S_OK)
1152 ERR("Couldn't register endpoint %s\n", debugstr_w(endpoint));
1154 /* FIXME: move remote unknown exporting into this function */
1156 start_apartment_remote_unknown();
1160 static HRESULT create_server(REFCLSID rclsid)
1162 static const WCHAR wszLocalServer32[] = { 'L','o','c','a','l','S','e','r','v','e','r','3','2',0 };
1163 static const WCHAR embedding[] = { ' ', '-','E','m','b','e','d','d','i','n','g',0 };
1166 WCHAR command[MAX_PATH+sizeof(embedding)/sizeof(WCHAR)];
1167 DWORD size = (MAX_PATH+1) * sizeof(WCHAR);
1169 PROCESS_INFORMATION pinfo;
1171 hres = COM_OpenKeyForCLSID(rclsid, wszLocalServer32, KEY_READ, &key);
1173 ERR("class %s not registered\n", debugstr_guid(rclsid));
1177 hres = RegQueryValueExW(key, NULL, NULL, NULL, (LPBYTE)command, &size);
1180 WARN("No default value for LocalServer32 key\n");
1181 return REGDB_E_CLASSNOTREG; /* FIXME: check retval */
1184 memset(&sinfo,0,sizeof(sinfo));
1185 sinfo.cb = sizeof(sinfo);
1187 /* EXE servers are started with the -Embedding switch. */
1189 strcatW(command, embedding);
1191 TRACE("activating local server %s for %s\n", debugstr_w(command), debugstr_guid(rclsid));
1193 /* FIXME: Win2003 supports a ServerExecutable value that is passed into
1195 if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo)) {
1196 WARN("failed to run local server %s\n", debugstr_w(command));
1197 return HRESULT_FROM_WIN32(GetLastError());
1199 CloseHandle(pinfo.hProcess);
1200 CloseHandle(pinfo.hThread);
1206 * start_local_service() - start a service given its name and parameters
1208 static DWORD start_local_service(LPCWSTR name, DWORD num, LPCWSTR *params)
1210 SC_HANDLE handle, hsvc;
1211 DWORD r = ERROR_FUNCTION_FAILED;
1213 TRACE("Starting service %s %d params\n", debugstr_w(name), num);
1215 handle = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
1218 hsvc = OpenServiceW(handle, name, SERVICE_START);
1221 if(StartServiceW(hsvc, num, params))
1225 if (r == ERROR_SERVICE_ALREADY_RUNNING)
1227 CloseServiceHandle(hsvc);
1231 CloseServiceHandle(handle);
1233 TRACE("StartService returned error %d (%s)\n", r, (r == ERROR_SUCCESS) ? "ok":"failed");
1239 * create_local_service() - start a COM server in a service
1241 * To start a Local Service, we read the AppID value under
1242 * the class's CLSID key, then open the HKCR\\AppId key specified
1243 * there and check for a LocalService value.
1245 * Note: Local Services are not supported under Windows 9x
1247 static HRESULT create_local_service(REFCLSID rclsid)
1250 WCHAR buf[CHARS_IN_GUID];
1251 static const WCHAR szLocalService[] = { 'L','o','c','a','l','S','e','r','v','i','c','e',0 };
1252 static const WCHAR szServiceParams[] = {'S','e','r','v','i','c','e','P','a','r','a','m','s',0};
1257 TRACE("Attempting to start Local service for %s\n", debugstr_guid(rclsid));
1259 hres = COM_OpenKeyForAppIdFromCLSID(rclsid, KEY_READ, &hkey);
1263 /* read the LocalService and ServiceParameters values from the AppID key */
1265 r = RegQueryValueExW(hkey, szLocalService, NULL, &type, (LPBYTE)buf, &sz);
1266 if (r==ERROR_SUCCESS && type==REG_SZ)
1269 LPWSTR args[1] = { NULL };
1272 * FIXME: I'm not really sure how to deal with the service parameters.
1273 * I suspect that the string returned from RegQueryValueExW
1274 * should be split into a number of arguments by spaces.
1275 * It would make more sense if ServiceParams contained a
1276 * REG_MULTI_SZ here, but it's a REG_SZ for the services
1277 * that I'm interested in for the moment.
1279 r = RegQueryValueExW(hkey, szServiceParams, NULL, &type, NULL, &sz);
1280 if (r == ERROR_SUCCESS && type == REG_SZ && sz)
1282 args[0] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz);
1284 RegQueryValueExW(hkey, szServiceParams, NULL, &type, (LPBYTE)args[0], &sz);
1286 r = start_local_service(buf, num_args, (LPCWSTR *)args);
1287 if (r != ERROR_SUCCESS)
1288 hres = REGDB_E_CLASSNOTREG; /* FIXME: check retval */
1289 HeapFree(GetProcessHeap(),0,args[0]);
1293 WARN("No LocalService value\n");
1294 hres = REGDB_E_CLASSNOTREG; /* FIXME: check retval */
1302 static void get_localserver_pipe_name(WCHAR *pipefn, REFCLSID rclsid)
1304 static const WCHAR wszPipeRef[] = {'\\','\\','.','\\','p','i','p','e','\\',0};
1305 strcpyW(pipefn, wszPipeRef);
1306 StringFromGUID2(rclsid, pipefn + sizeof(wszPipeRef)/sizeof(wszPipeRef[0]) - 1, CHARS_IN_GUID);
1309 /* FIXME: should call to rpcss instead */
1310 HRESULT RPC_GetLocalClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
1315 DWORD res, bufferlen;
1316 char marshalbuffer[200];
1318 LARGE_INTEGER seekto;
1319 ULARGE_INTEGER newpos;
1322 static const int MAXTRIES = 30; /* 30 seconds */
1324 TRACE("rclsid=%s, iid=%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1326 get_localserver_pipe_name(pipefn, rclsid);
1328 while (tries++ < MAXTRIES) {
1329 TRACE("waiting for %s\n", debugstr_w(pipefn));
1331 WaitNamedPipeW( pipefn, NMPWAIT_WAIT_FOREVER );
1332 hPipe = CreateFileW(pipefn, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1333 if (hPipe == INVALID_HANDLE_VALUE) {
1335 if ( (hres = create_local_service(rclsid)) &&
1336 (hres = create_server(rclsid)) )
1340 WARN("Connecting to %s, no response yet, retrying: le is %x\n", debugstr_w(pipefn), GetLastError());
1346 if (!ReadFile(hPipe,marshalbuffer,sizeof(marshalbuffer),&bufferlen,NULL)) {
1347 FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid));
1351 TRACE("read marshal id from pipe\n");
1356 if (tries >= MAXTRIES)
1357 return E_NOINTERFACE;
1359 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
1360 if (hres) return hres;
1361 hres = IStream_Write(pStm,marshalbuffer,bufferlen,&res);
1363 seekto.u.LowPart = 0;seekto.u.HighPart = 0;
1364 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
1366 TRACE("unmarshalling classfactory\n");
1367 hres = CoUnmarshalInterface(pStm,&IID_IClassFactory,ppv);
1369 IStream_Release(pStm);
1374 struct local_server_params
1381 /* FIXME: should call to rpcss instead */
1382 static DWORD WINAPI local_server_thread(LPVOID param)
1384 struct local_server_params * lsp = (struct local_server_params *)param;
1388 IStream *pStm = lsp->stream;
1390 unsigned char *buffer;
1392 LARGE_INTEGER seekto;
1393 ULARGE_INTEGER newpos;
1396 TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid));
1398 get_localserver_pipe_name(pipefn, &lsp->clsid);
1400 hPipe = CreateNamedPipeW( pipefn, PIPE_ACCESS_DUPLEX,
1401 PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
1402 4096, 4096, 500 /* 0.5 second timeout */, NULL );
1404 SetEvent(lsp->ready_event);
1406 HeapFree(GetProcessHeap(), 0, lsp);
1408 if (hPipe == INVALID_HANDLE_VALUE)
1410 FIXME("pipe creation failed for %s, le is %d\n", debugstr_w(pipefn), GetLastError());
1415 if (!ConnectNamedPipe(hPipe,NULL) && GetLastError() != ERROR_PIPE_CONNECTED) {
1416 ERR("Failure during ConnectNamedPipe %d, ABORT!\n",GetLastError());
1420 TRACE("marshalling IClassFactory to client\n");
1422 hres = IStream_Stat(pStm,&ststg,0);
1423 if (hres) return hres;
1425 seekto.u.LowPart = 0;
1426 seekto.u.HighPart = 0;
1427 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
1429 FIXME("IStream_Seek failed, %x\n",hres);
1433 buflen = ststg.cbSize.u.LowPart;
1434 buffer = HeapAlloc(GetProcessHeap(),0,buflen);
1436 hres = IStream_Read(pStm,buffer,buflen,&res);
1438 FIXME("Stream Read failed, %x\n",hres);
1439 HeapFree(GetProcessHeap(),0,buffer);
1443 WriteFile(hPipe,buffer,buflen,&res,NULL);
1444 HeapFree(GetProcessHeap(),0,buffer);
1446 FlushFileBuffers(hPipe);
1447 DisconnectNamedPipe(hPipe);
1449 TRACE("done marshalling IClassFactory\n");
1452 IStream_Release(pStm);
1456 void RPC_StartLocalServer(REFCLSID clsid, IStream *stream)
1459 HANDLE thread, ready_event;
1460 struct local_server_params *lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp));
1462 lsp->clsid = *clsid;
1463 lsp->stream = stream;
1464 IStream_AddRef(stream);
1465 lsp->ready_event = ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1467 thread = CreateThread(NULL, 0, local_server_thread, lsp, 0, &tid);
1468 CloseHandle(thread);
1469 /* FIXME: failure handling */
1471 WaitForSingleObject(ready_event, INFINITE);
1472 CloseHandle(ready_event);