ole32: Pass in the IID and IUnknown* of the object being executed to the server notif...
[wine/multimedia.git] / dlls / ole32 / rpc.c
blob586562ec3a6d005b912250e2456d8be8834eeb55
1 /*
2 * RPC Manager
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
23 #include "config.h"
24 #include "wine/port.h"
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <assert.h>
32 #define COBJMACROS
33 #define NONAMELESSUNION
34 #define NONAMELESSSTRUCT
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winuser.h"
39 #include "winsvc.h"
40 #include "objbase.h"
41 #include "ole2.h"
42 #include "rpc.h"
43 #include "winerror.h"
44 #include "winreg.h"
45 #include "wtypes.h"
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 =
65 0, 0, &csRegIf,
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 =
75 0, 0, &csChannelHook,
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};
84 struct registered_if
86 struct list entry;
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);
99 typedef struct
101 const IRpcChannelBufferVtbl *lpVtbl;
102 LONG refs;
103 } RpcChannelBuffer;
105 typedef struct
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 IID iid; /* ID of interface being called */
122 IUnknown *iface; /* interface being called */
123 HANDLE handle; /* handle that will become signaled when call finishes */
124 RPC_STATUS status; /* status (out) */
125 HRESULT hr; /* hresult (out) */
128 struct message_state
130 RPC_BINDING_HANDLE binding_handle;
131 ULONG prefix_data_len;
132 SChannelHookCallInfo channel_hook_info;
135 typedef struct
137 ULONG conformance; /* NDR */
138 GUID id;
139 ULONG size;
140 /* [size_is((size+7)&~7)] */ unsigned char data[1];
141 } WIRE_ORPC_EXTENT;
143 struct channel_hook_entry
145 struct list entry;
146 GUID id;
147 IChannelHook *hook;
150 struct channel_hook_buffer_data
152 GUID id;
153 ULONG extension_size;
157 /* Channel Hook Functions */
159 static ULONG ChannelHooks_ClientGetSize(SChannelHookCallInfo *info,
160 struct channel_hook_buffer_data **data, unsigned int *hook_count,
161 ULONG *extension_count)
163 struct channel_hook_entry *entry;
164 ULONG total_size = 0;
165 unsigned int hook_index = 0;
167 *hook_count = 0;
168 *extension_count = 0;
170 EnterCriticalSection(&csChannelHook);
172 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
173 (*hook_count)++;
175 if (hook_count)
176 *data = HeapAlloc(GetProcessHeap(), 0, *hook_count * sizeof(struct channel_hook_buffer_data));
177 else
178 *data = NULL;
180 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
182 ULONG extension_size = 0;
184 IChannelHook_ClientGetSize(entry->hook, &entry->id, &info->iid, &extension_size);
186 TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size);
188 extension_size = (extension_size+7)&~7;
189 (*data)[hook_index].id = entry->id;
190 (*data)[hook_index].extension_size = extension_size;
192 /* an extension is only put onto the wire if it has data to write */
193 if (extension_size)
195 total_size += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[extension_size]);
196 (*extension_count)++;
199 hook_index++;
202 LeaveCriticalSection(&csChannelHook);
204 return total_size;
207 static unsigned char * ChannelHooks_ClientFillBuffer(SChannelHookCallInfo *info,
208 unsigned char *buffer, struct channel_hook_buffer_data *data,
209 unsigned int hook_count)
211 struct channel_hook_entry *entry;
213 EnterCriticalSection(&csChannelHook);
215 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
217 unsigned int i;
218 ULONG extension_size = 0;
219 WIRE_ORPC_EXTENT *wire_orpc_extent = (WIRE_ORPC_EXTENT *)buffer;
221 for (i = 0; i < hook_count; i++)
222 if (IsEqualGUID(&entry->id, &data[i].id))
223 extension_size = data[i].extension_size;
225 /* an extension is only put onto the wire if it has data to write */
226 if (!extension_size)
227 continue;
229 IChannelHook_ClientFillBuffer(entry->hook, &entry->id, &info->iid,
230 &extension_size, buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]));
232 TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size);
234 /* FIXME: set unused portion of wire_orpc_extent->data to 0? */
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]);
242 LeaveCriticalSection(&csChannelHook);
244 HeapFree(GetProcessHeap(), 0, data);
246 return buffer;
249 static void ChannelHooks_ServerNotify(SChannelHookCallInfo *info,
250 DWORD lDataRep, WIRE_ORPC_EXTENT *first_wire_orpc_extent,
251 ULONG extension_count)
253 struct channel_hook_entry *entry;
254 ULONG i;
256 EnterCriticalSection(&csChannelHook);
258 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
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])
265 if (IsEqualGUID(&entry->id, &wire_orpc_extent->id))
266 break;
268 if (i == extension_count) wire_orpc_extent = NULL;
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);
276 LeaveCriticalSection(&csChannelHook);
279 HRESULT RPC_RegisterChannelHook(REFGUID rguid, IChannelHook *hook)
281 struct channel_hook_entry *entry;
283 TRACE("(%s, %p)\n", debugstr_guid(rguid), hook);
285 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
286 if (!entry)
287 return E_OUTOFMEMORY;
289 memcpy(&entry->id, rguid, sizeof(entry->id));
290 entry->hook = hook;
291 IChannelHook_AddRef(hook);
293 EnterCriticalSection(&csChannelHook);
294 list_add_tail(&channel_hooks, &entry->entry);
295 LeaveCriticalSection(&csChannelHook);
297 return S_OK;
300 void RPC_UnregisterAllChannelHooks(void)
302 struct channel_hook_entry *cursor;
303 struct channel_hook_entry *cursor2;
305 EnterCriticalSection(&csChannelHook);
306 LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &channel_hooks, struct channel_hook_entry, entry)
307 HeapFree(GetProcessHeap(), 0, cursor);
308 LeaveCriticalSection(&csChannelHook);
311 /* RPC Channel Buffer Functions */
313 static HRESULT WINAPI RpcChannelBuffer_QueryInterface(LPRPCCHANNELBUFFER iface, REFIID riid, LPVOID *ppv)
315 *ppv = NULL;
316 if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown))
318 *ppv = (LPVOID)iface;
319 IUnknown_AddRef(iface);
320 return S_OK;
322 return E_NOINTERFACE;
325 static ULONG WINAPI RpcChannelBuffer_AddRef(LPRPCCHANNELBUFFER iface)
327 RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
328 return InterlockedIncrement(&This->refs);
331 static ULONG WINAPI ServerRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface)
333 RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
334 ULONG ref;
336 ref = InterlockedDecrement(&This->refs);
337 if (ref)
338 return ref;
340 HeapFree(GetProcessHeap(), 0, This);
341 return 0;
344 static ULONG WINAPI ClientRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface)
346 ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
347 ULONG ref;
349 ref = InterlockedDecrement(&This->super.refs);
350 if (ref)
351 return ref;
353 if (This->event) CloseHandle(This->event);
354 RpcBindingFree(&This->bind);
355 HeapFree(GetProcessHeap(), 0, This);
356 return 0;
359 static HRESULT WINAPI ServerRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
361 RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
362 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
363 RPC_STATUS status;
364 struct message_state *message_state;
366 TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid));
368 message_state = (struct message_state *)msg->Handle;
369 /* restore the binding handle and the real start of data */
370 msg->Handle = message_state->binding_handle;
371 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
373 status = I_RpcGetBuffer(msg);
375 /* save away the message state again */
376 msg->Handle = message_state;
377 message_state->prefix_data_len = 0;
379 TRACE("-- %ld\n", status);
381 return HRESULT_FROM_WIN32(status);
384 static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
386 ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
387 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
388 RPC_CLIENT_INTERFACE *cif;
389 RPC_STATUS status;
390 ORPCTHIS *orpcthis;
391 struct message_state *message_state;
392 ULONG extensions_size;
393 struct channel_hook_buffer_data *channel_hook_data;
394 unsigned int channel_hook_count;
395 ULONG extension_count;
397 TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid));
399 cif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_CLIENT_INTERFACE));
400 if (!cif)
401 return E_OUTOFMEMORY;
403 message_state = HeapAlloc(GetProcessHeap(), 0, sizeof(*message_state));
404 if (!message_state)
406 HeapFree(GetProcessHeap(), 0, cif);
407 return E_OUTOFMEMORY;
410 cif->Length = sizeof(RPC_CLIENT_INTERFACE);
411 /* RPC interface ID = COM interface ID */
412 cif->InterfaceId.SyntaxGUID = *riid;
413 /* COM objects always have a version of 0.0 */
414 cif->InterfaceId.SyntaxVersion.MajorVersion = 0;
415 cif->InterfaceId.SyntaxVersion.MinorVersion = 0;
416 msg->Handle = This->bind;
417 msg->RpcInterfaceInformation = cif;
419 message_state->channel_hook_info.iid = *riid;
420 message_state->channel_hook_info.cbSize = sizeof(message_state->channel_hook_info);
421 message_state->channel_hook_info.uCausality = GUID_NULL; /* FIXME */
422 message_state->channel_hook_info.dwServerPid = 0; /* FIXME */
423 message_state->channel_hook_info.iMethod = msg->ProcNum;
424 message_state->channel_hook_info.pObject = NULL; /* only present on server-side */
426 extensions_size = ChannelHooks_ClientGetSize(&message_state->channel_hook_info,
427 &channel_hook_data, &channel_hook_count, &extension_count);
429 msg->BufferLength += FIELD_OFFSET(ORPCTHIS, extensions) + 4;
430 if (extensions_size)
432 msg->BufferLength += FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent) + 2*sizeof(DWORD) + extensions_size;
433 if (extension_count & 1)
434 msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
437 status = I_RpcGetBuffer(msg);
439 message_state->prefix_data_len = 0;
440 message_state->binding_handle = This->bind;
441 msg->Handle = message_state;
443 if (status == RPC_S_OK)
445 orpcthis = (ORPCTHIS *)msg->Buffer;
446 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPCTHIS, extensions);
448 orpcthis->version.MajorVersion = COM_MAJOR_VERSION;
449 orpcthis->version.MinorVersion = COM_MINOR_VERSION;
450 orpcthis->flags = message_state->channel_hook_info.dwServerPid ? ORPCF_LOCAL : ORPCF_NULL;
451 orpcthis->reserved1 = 0;
452 orpcthis->cid = message_state->channel_hook_info.uCausality;
454 /* NDR representation of orpcthis->extensions */
455 *(DWORD *)msg->Buffer = extensions_size ? 1 : 0;
456 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
458 if (extensions_size)
460 ORPC_EXTENT_ARRAY *orpc_extent_array = msg->Buffer;
461 orpc_extent_array->size = extension_count;
462 orpc_extent_array->reserved = 0;
463 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent);
464 /* NDR representation of orpc_extent_array->extent */
465 *(DWORD *)msg->Buffer = 1;
466 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
467 /* NDR representation of [size_is] attribute of orpc_extent_array->extent */
468 *(DWORD *)msg->Buffer = (extension_count + 1) & ~1;
469 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
471 msg->Buffer = ChannelHooks_ClientFillBuffer(&message_state->channel_hook_info,
472 msg->Buffer, channel_hook_data, channel_hook_count);
474 /* we must add a dummy extension if there is an odd extension
475 * count to meet the contract specified by the size_is attribute */
476 if (extension_count & 1)
478 WIRE_ORPC_EXTENT *wire_orpc_extent = msg->Buffer;
479 wire_orpc_extent->conformance = 0;
480 memcpy(&wire_orpc_extent->id, &GUID_NULL, sizeof(wire_orpc_extent->id));
481 wire_orpc_extent->size = 0;
482 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
486 /* store the prefixed data length so that we can restore the real buffer
487 * pointer in ClientRpcChannelBuffer_SendReceive. */
488 message_state->prefix_data_len = (char *)msg->Buffer - (char *)orpcthis;
489 msg->BufferLength -= message_state->prefix_data_len;
492 TRACE("-- %ld\n", status);
494 return HRESULT_FROM_WIN32(status);
497 static HRESULT WINAPI ServerRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus)
499 FIXME("stub\n");
500 return E_NOTIMPL;
503 static HANDLE ClientRpcChannelBuffer_GetEventHandle(ClientRpcChannelBuffer *This)
505 HANDLE event = InterlockedExchangePointer(&This->event, NULL);
507 /* Note: must be auto-reset event so we can reuse it without a call
508 * to ResetEvent */
509 if (!event) event = CreateEventW(NULL, FALSE, FALSE, NULL);
511 return event;
514 static void ClientRpcChannelBuffer_ReleaseEventHandle(ClientRpcChannelBuffer *This, HANDLE event)
516 if (InterlockedCompareExchangePointer(&This->event, event, NULL))
517 /* already a handle cached in This */
518 CloseHandle(event);
521 /* this thread runs an outgoing RPC */
522 static DWORD WINAPI rpc_sendreceive_thread(LPVOID param)
524 struct dispatch_params *data = (struct dispatch_params *) param;
526 /* FIXME: trap and rethrow RPC exceptions in app thread */
527 data->status = I_RpcSendReceive((RPC_MESSAGE *)data->msg);
529 TRACE("completed with status 0x%lx\n", data->status);
531 SetEvent(data->handle);
533 return 0;
536 static inline HRESULT ClientRpcChannelBuffer_IsCorrectApartment(ClientRpcChannelBuffer *This, APARTMENT *apt)
538 OXID oxid;
539 if (!apt)
540 return S_FALSE;
541 if (apartment_getoxid(apt, &oxid) != S_OK)
542 return S_FALSE;
543 if (This->oxid != oxid)
544 return S_FALSE;
545 return S_OK;
548 static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus)
550 ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
551 HRESULT hr;
552 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
553 RPC_STATUS status;
554 DWORD index;
555 struct dispatch_params *params;
556 APARTMENT *apt = NULL;
557 IPID ipid;
558 struct message_state *message_state;
560 TRACE("(%p) iMethod=%d\n", olemsg, olemsg->iMethod);
562 hr = ClientRpcChannelBuffer_IsCorrectApartment(This, COM_CurrentApt());
563 if (hr != S_OK)
565 ERR("called from wrong apartment, should have been 0x%s\n",
566 wine_dbgstr_longlong(This->oxid));
567 return RPC_E_WRONG_THREAD;
570 params = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*params));
571 if (!params) return E_OUTOFMEMORY;
573 message_state = (struct message_state *)msg->Handle;
574 /* restore the binding handle and the real start of data */
575 msg->Handle = message_state->binding_handle;
576 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
577 msg->BufferLength += message_state->prefix_data_len;
579 params->msg = olemsg;
580 params->status = RPC_S_OK;
581 params->hr = S_OK;
583 /* Note: this is an optimization in the Microsoft OLE runtime that we need
584 * to copy, as shown by the test_no_couninitialize_client test. without
585 * short-circuiting the RPC runtime in the case below, the test will
586 * deadlock on the loader lock due to the RPC runtime needing to create
587 * a thread to process the RPC when this function is called indirectly
588 * from DllMain */
590 RpcBindingInqObject(message_state->binding_handle, &ipid);
591 hr = ipid_get_dispatch_params(&ipid, &apt, &params->stub, &params->chan,
592 &params->iid, &params->iface);
593 params->handle = ClientRpcChannelBuffer_GetEventHandle(This);
594 if ((hr == S_OK) && !apt->multi_threaded)
596 TRACE("Calling apartment thread 0x%08x...\n", apt->tid);
598 if (!PostMessageW(apartment_getwindow(apt), DM_EXECUTERPC, 0, (LPARAM)params))
600 ERR("PostMessage failed with error %d\n", GetLastError());
601 hr = HRESULT_FROM_WIN32(GetLastError());
604 else
606 if (hr == S_OK)
608 /* otherwise, we go via RPC runtime so the stub and channel aren't
609 * needed here */
610 IRpcStubBuffer_Release(params->stub);
611 params->stub = NULL;
612 IRpcChannelBuffer_Release(params->chan);
613 params->chan = NULL;
616 /* we use a separate thread here because we need to be able to
617 * pump the message loop in the application thread: if we do not,
618 * any windows created by this thread will hang and RPCs that try
619 * and re-enter this STA from an incoming server thread will
620 * deadlock. InstallShield is an example of that.
622 if (!QueueUserWorkItem(rpc_sendreceive_thread, params, WT_EXECUTEDEFAULT))
624 ERR("QueueUserWorkItem failed with error %x\n", GetLastError());
625 hr = E_UNEXPECTED;
627 else
628 hr = S_OK;
630 if (apt) apartment_release(apt);
632 if (hr == S_OK)
634 if (WaitForSingleObject(params->handle, 0))
635 hr = CoWaitForMultipleHandles(0, INFINITE, 1, &params->handle, &index);
637 ClientRpcChannelBuffer_ReleaseEventHandle(This, params->handle);
639 /* save away the message state again */
640 msg->Handle = message_state;
641 message_state->prefix_data_len = 0;
643 if (hr == S_OK) hr = params->hr;
645 status = params->status;
646 HeapFree(GetProcessHeap(), 0, params);
647 params = NULL;
649 if (hr) return hr;
651 if (pstatus) *pstatus = status;
653 TRACE("RPC call status: 0x%lx\n", status);
654 if (status == RPC_S_OK)
655 hr = S_OK;
656 else if (status == RPC_S_CALL_FAILED)
657 hr = *(HRESULT *)olemsg->Buffer;
658 else
659 hr = HRESULT_FROM_WIN32(status);
661 TRACE("-- 0x%08x\n", hr);
663 return hr;
666 static HRESULT WINAPI ServerRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
668 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
669 RPC_STATUS status;
670 struct message_state *message_state;
672 TRACE("(%p)\n", msg);
674 message_state = (struct message_state *)msg->Handle;
675 /* restore the binding handle and the real start of data */
676 msg->Handle = message_state->binding_handle;
677 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
678 msg->BufferLength += message_state->prefix_data_len;
679 message_state->prefix_data_len = 0;
681 status = I_RpcFreeBuffer(msg);
683 msg->Handle = message_state;
685 TRACE("-- %ld\n", status);
687 return HRESULT_FROM_WIN32(status);
690 static HRESULT WINAPI ClientRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
692 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
693 RPC_STATUS status;
694 struct message_state *message_state;
696 TRACE("(%p)\n", msg);
698 message_state = (struct message_state *)msg->Handle;
699 /* restore the binding handle and the real start of data */
700 msg->Handle = message_state->binding_handle;
701 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
702 msg->BufferLength += message_state->prefix_data_len;
704 status = I_RpcFreeBuffer(msg);
706 HeapFree(GetProcessHeap(), 0, msg->RpcInterfaceInformation);
707 msg->RpcInterfaceInformation = NULL;
708 HeapFree(GetProcessHeap(), 0, message_state);
710 TRACE("-- %ld\n", status);
712 return HRESULT_FROM_WIN32(status);
715 static HRESULT WINAPI ClientRpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext)
717 ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
719 TRACE("(%p,%p)\n", pdwDestContext, ppvDestContext);
721 *pdwDestContext = This->dest_context;
722 *ppvDestContext = This->dest_context_data;
724 return S_OK;
727 static HRESULT WINAPI ServerRpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext)
729 FIXME("(%p,%p), stub!\n", pdwDestContext, ppvDestContext);
730 return E_FAIL;
733 static HRESULT WINAPI RpcChannelBuffer_IsConnected(LPRPCCHANNELBUFFER iface)
735 TRACE("()\n");
736 /* native does nothing too */
737 return S_OK;
740 static const IRpcChannelBufferVtbl ClientRpcChannelBufferVtbl =
742 RpcChannelBuffer_QueryInterface,
743 RpcChannelBuffer_AddRef,
744 ClientRpcChannelBuffer_Release,
745 ClientRpcChannelBuffer_GetBuffer,
746 ClientRpcChannelBuffer_SendReceive,
747 ClientRpcChannelBuffer_FreeBuffer,
748 ClientRpcChannelBuffer_GetDestCtx,
749 RpcChannelBuffer_IsConnected
752 static const IRpcChannelBufferVtbl ServerRpcChannelBufferVtbl =
754 RpcChannelBuffer_QueryInterface,
755 RpcChannelBuffer_AddRef,
756 ServerRpcChannelBuffer_Release,
757 ServerRpcChannelBuffer_GetBuffer,
758 ServerRpcChannelBuffer_SendReceive,
759 ServerRpcChannelBuffer_FreeBuffer,
760 ServerRpcChannelBuffer_GetDestCtx,
761 RpcChannelBuffer_IsConnected
764 /* returns a channel buffer for proxies */
765 HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid,
766 DWORD dest_context, void *dest_context_data,
767 IRpcChannelBuffer **chan)
769 ClientRpcChannelBuffer *This;
770 WCHAR endpoint[200];
771 RPC_BINDING_HANDLE bind;
772 RPC_STATUS status;
773 LPWSTR string_binding;
775 /* connect to the apartment listener thread */
776 get_rpc_endpoint(endpoint, oxid);
778 TRACE("proxy pipe: connecting to endpoint: %s\n", debugstr_w(endpoint));
780 status = RpcStringBindingComposeW(
781 NULL,
782 wszRpcTransport,
783 NULL,
784 endpoint,
785 NULL,
786 &string_binding);
788 if (status == RPC_S_OK)
790 status = RpcBindingFromStringBindingW(string_binding, &bind);
792 if (status == RPC_S_OK)
794 IPID ipid2 = *ipid; /* why can't RpcBindingSetObject take a const? */
795 status = RpcBindingSetObject(bind, &ipid2);
796 if (status != RPC_S_OK)
797 RpcBindingFree(&bind);
800 RpcStringFreeW(&string_binding);
803 if (status != RPC_S_OK)
805 ERR("Couldn't get binding for endpoint %s, status = %ld\n", debugstr_w(endpoint), status);
806 return HRESULT_FROM_WIN32(status);
809 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
810 if (!This)
812 RpcBindingFree(&bind);
813 return E_OUTOFMEMORY;
816 This->super.lpVtbl = &ClientRpcChannelBufferVtbl;
817 This->super.refs = 1;
818 This->bind = bind;
819 apartment_getoxid(COM_CurrentApt(), &This->oxid);
820 This->dest_context = dest_context;
821 This->dest_context_data = dest_context_data;
822 This->event = NULL;
824 *chan = (IRpcChannelBuffer*)This;
826 return S_OK;
829 HRESULT RPC_CreateServerChannel(IRpcChannelBuffer **chan)
831 RpcChannelBuffer *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
832 if (!This)
833 return E_OUTOFMEMORY;
835 This->lpVtbl = &ServerRpcChannelBufferVtbl;
836 This->refs = 1;
838 *chan = (IRpcChannelBuffer*)This;
840 return S_OK;
843 /* unmarshals ORPCTHIS according to NDR rules, but doesn't allocate any memory */
844 static HRESULT unmarshal_ORPCTHIS(RPC_MESSAGE *msg, ORPCTHIS *orpcthis,
845 ORPC_EXTENT_ARRAY *orpc_ext_array, WIRE_ORPC_EXTENT **first_wire_orpc_extent)
847 const char *end = (char *)msg->Buffer + msg->BufferLength;
849 *first_wire_orpc_extent = NULL;
851 if (msg->BufferLength < FIELD_OFFSET(ORPCTHIS, extensions) + 4)
853 ERR("invalid buffer length\n");
854 return RPC_E_INVALID_HEADER;
857 memcpy(orpcthis, msg->Buffer, FIELD_OFFSET(ORPCTHIS, extensions));
858 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPCTHIS, extensions);
860 if ((const char *)msg->Buffer + sizeof(DWORD) > end)
861 return RPC_E_INVALID_HEADER;
863 if (*(DWORD *)msg->Buffer)
864 orpcthis->extensions = orpc_ext_array;
865 else
866 orpcthis->extensions = NULL;
868 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
870 if (orpcthis->extensions)
872 DWORD pointer_id;
873 DWORD i;
875 memcpy(orpcthis->extensions, msg->Buffer, FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent));
876 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(ORPC_EXTENT_ARRAY, extent);
878 if ((const char *)msg->Buffer + 2 * sizeof(DWORD) > end)
879 return RPC_E_INVALID_HEADER;
881 pointer_id = *(DWORD *)msg->Buffer;
882 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
883 orpcthis->extensions->extent = NULL;
885 if (pointer_id)
887 WIRE_ORPC_EXTENT *wire_orpc_extent;
889 /* conformance */
890 if (*(DWORD *)msg->Buffer != ((orpcthis->extensions->size+1)&~1))
891 return RPC_S_INVALID_BOUND;
893 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
895 /* arbritary limit for security (don't know what native does) */
896 if (orpcthis->extensions->size > 256)
898 ERR("too many extensions: %ld\n", orpcthis->extensions->size);
899 return RPC_S_INVALID_BOUND;
902 *first_wire_orpc_extent = wire_orpc_extent = (WIRE_ORPC_EXTENT *)msg->Buffer;
903 for (i = 0; i < ((orpcthis->extensions->size+1)&~1); i++)
905 if ((const char *)&wire_orpc_extent->data[0] > end)
906 return RPC_S_INVALID_BOUND;
907 if (wire_orpc_extent->conformance != ((wire_orpc_extent->size+7)&~7))
908 return RPC_S_INVALID_BOUND;
909 if ((const char *)&wire_orpc_extent->data[wire_orpc_extent->conformance] > end)
910 return RPC_S_INVALID_BOUND;
911 TRACE("size %u, guid %s\n", wire_orpc_extent->size, debugstr_guid(&wire_orpc_extent->id));
912 wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance];
914 msg->Buffer = wire_orpc_extent;
918 if ((orpcthis->version.MajorVersion != COM_MAJOR_VERSION) ||
919 (orpcthis->version.MinorVersion > COM_MINOR_VERSION))
921 ERR("COM version {%d, %d} not supported\n",
922 orpcthis->version.MajorVersion, orpcthis->version.MinorVersion);
923 return RPC_E_VERSION_MISMATCH;
926 if (orpcthis->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4))
928 ERR("invalid flags 0x%lx\n", orpcthis->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4));
929 return RPC_E_INVALID_HEADER;
932 return S_OK;
935 void RPC_ExecuteCall(struct dispatch_params *params)
937 struct message_state *message_state = NULL;
938 RPC_MESSAGE *msg = (RPC_MESSAGE *)params->msg;
939 char *original_buffer = msg->Buffer;
940 ORPCTHIS orpcthis;
941 ORPC_EXTENT_ARRAY orpc_ext_array;
942 WIRE_ORPC_EXTENT *first_wire_orpc_extent;
944 /* handle ORPCTHIS and server extensions */
946 params->hr = unmarshal_ORPCTHIS(msg, &orpcthis, &orpc_ext_array, &first_wire_orpc_extent);
947 if (params->hr != S_OK)
948 goto exit;
950 message_state = HeapAlloc(GetProcessHeap(), 0, sizeof(*message_state));
951 if (!message_state)
953 params->hr = E_OUTOFMEMORY;
954 goto exit;
957 message_state->prefix_data_len = original_buffer - (char *)msg->Buffer;
958 message_state->binding_handle = msg->Handle;
960 message_state->channel_hook_info.iid = params->iid;
961 message_state->channel_hook_info.cbSize = sizeof(message_state->channel_hook_info);
962 message_state->channel_hook_info.uCausality = orpcthis.cid;
963 message_state->channel_hook_info.dwServerPid = GetCurrentProcessId();
964 message_state->channel_hook_info.iMethod = msg->ProcNum;
965 message_state->channel_hook_info.pObject = params->iface;
967 if (orpcthis.extensions && first_wire_orpc_extent &&
968 orpcthis.extensions->size)
969 ChannelHooks_ServerNotify(&message_state->channel_hook_info, msg->DataRepresentation, first_wire_orpc_extent, orpcthis.extensions->size);
971 msg->Handle = message_state;
972 msg->BufferLength -= message_state->prefix_data_len;
974 /* call message filter */
976 if (COM_CurrentApt()->filter)
978 DWORD handlecall;
979 INTERFACEINFO interface_info;
981 interface_info.pUnk = params->iface;
982 interface_info.iid = params->iid;
983 interface_info.wMethod = msg->ProcNum;
984 handlecall = IMessageFilter_HandleInComingCall(COM_CurrentApt()->filter,
985 CALLTYPE_TOPLEVEL /* FIXME */,
986 (HTASK)GetCurrentProcessId(),
987 0 /* FIXME */,
988 &interface_info);
989 TRACE("IMessageFilter_HandleInComingCall returned %d\n", handlecall);
990 switch (handlecall)
992 case SERVERCALL_REJECTED:
993 params->hr = RPC_E_CALL_REJECTED;
994 goto exit;
995 case SERVERCALL_RETRYLATER:
996 #if 0 /* FIXME: handle retries on the client side before enabling this code */
997 params->hr = RPC_E_RETRY;
998 goto exit;
999 #else
1000 FIXME("retry call later not implemented\n");
1001 break;
1002 #endif
1003 case SERVERCALL_ISHANDLED:
1004 default:
1005 break;
1009 /* invoke the method */
1011 params->hr = IRpcStubBuffer_Invoke(params->stub, params->msg, params->chan);
1013 message_state = (struct message_state *)msg->Handle;
1014 msg->Handle = message_state->binding_handle;
1015 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
1016 msg->BufferLength += message_state->prefix_data_len;
1018 exit:
1019 HeapFree(GetProcessHeap(), 0, message_state);
1020 IRpcStubBuffer_Release(params->stub);
1021 IRpcChannelBuffer_Release(params->chan);
1022 if (params->handle) SetEvent(params->handle);
1025 static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg)
1027 struct dispatch_params *params;
1028 APARTMENT *apt;
1029 IPID ipid;
1030 HRESULT hr;
1032 RpcBindingInqObject(msg->Handle, &ipid);
1034 TRACE("ipid = %s, iMethod = %d\n", debugstr_guid(&ipid), msg->ProcNum);
1036 params = HeapAlloc(GetProcessHeap(), 0, sizeof(*params));
1037 if (!params) return RpcRaiseException(E_OUTOFMEMORY);
1039 hr = ipid_get_dispatch_params(&ipid, &apt, &params->stub, &params->chan,
1040 &params->iid, &params->iface);
1041 if (hr != S_OK)
1043 ERR("no apartment found for ipid %s\n", debugstr_guid(&ipid));
1044 HeapFree(GetProcessHeap(), 0, params);
1045 return RpcRaiseException(hr);
1048 params->msg = (RPCOLEMESSAGE *)msg;
1049 params->status = RPC_S_OK;
1050 params->hr = S_OK;
1051 params->handle = NULL;
1053 /* Note: this is the important difference between STAs and MTAs - we
1054 * always execute RPCs to STAs in the thread that originally created the
1055 * apartment (i.e. the one that pumps messages to the window) */
1056 if (!apt->multi_threaded)
1058 params->handle = CreateEventW(NULL, FALSE, FALSE, NULL);
1060 TRACE("Calling apartment thread 0x%08x...\n", apt->tid);
1062 if (PostMessageW(apartment_getwindow(apt), DM_EXECUTERPC, 0, (LPARAM)params))
1063 WaitForSingleObject(params->handle, INFINITE);
1064 else
1066 ERR("PostMessage failed with error %d\n", GetLastError());
1067 IRpcChannelBuffer_Release(params->chan);
1068 IRpcStubBuffer_Release(params->stub);
1070 CloseHandle(params->handle);
1072 else
1074 BOOL joined = FALSE;
1075 if (!COM_CurrentInfo()->apt)
1077 apartment_joinmta();
1078 joined = TRUE;
1080 RPC_ExecuteCall(params);
1081 if (joined)
1083 apartment_release(COM_CurrentInfo()->apt);
1084 COM_CurrentInfo()->apt = NULL;
1088 hr = params->hr;
1089 HeapFree(GetProcessHeap(), 0, params);
1091 apartment_release(apt);
1093 /* if IRpcStubBuffer_Invoke fails, we should raise an exception to tell
1094 * the RPC runtime that the call failed */
1095 if (hr) RpcRaiseException(hr);
1098 /* stub registration */
1099 HRESULT RPC_RegisterInterface(REFIID riid)
1101 struct registered_if *rif;
1102 BOOL found = FALSE;
1103 HRESULT hr = S_OK;
1105 TRACE("(%s)\n", debugstr_guid(riid));
1107 EnterCriticalSection(&csRegIf);
1108 LIST_FOR_EACH_ENTRY(rif, &registered_interfaces, struct registered_if, entry)
1110 if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid))
1112 rif->refs++;
1113 found = TRUE;
1114 break;
1117 if (!found)
1119 TRACE("Creating new interface\n");
1121 rif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rif));
1122 if (rif)
1124 RPC_STATUS status;
1126 rif->refs = 1;
1127 rif->If.Length = sizeof(RPC_SERVER_INTERFACE);
1128 /* RPC interface ID = COM interface ID */
1129 rif->If.InterfaceId.SyntaxGUID = *riid;
1130 rif->If.DispatchTable = &rpc_dispatch;
1131 /* all other fields are 0, including the version asCOM objects
1132 * always have a version of 0.0 */
1133 status = RpcServerRegisterIfEx(
1134 (RPC_IF_HANDLE)&rif->If,
1135 NULL, NULL,
1136 RPC_IF_OLE | RPC_IF_AUTOLISTEN,
1137 RPC_C_LISTEN_MAX_CALLS_DEFAULT,
1138 NULL);
1139 if (status == RPC_S_OK)
1140 list_add_tail(&registered_interfaces, &rif->entry);
1141 else
1143 ERR("RpcServerRegisterIfEx failed with error %ld\n", status);
1144 HeapFree(GetProcessHeap(), 0, rif);
1145 hr = HRESULT_FROM_WIN32(status);
1148 else
1149 hr = E_OUTOFMEMORY;
1151 LeaveCriticalSection(&csRegIf);
1152 return hr;
1155 /* stub unregistration */
1156 void RPC_UnregisterInterface(REFIID riid)
1158 struct registered_if *rif;
1159 EnterCriticalSection(&csRegIf);
1160 LIST_FOR_EACH_ENTRY(rif, &registered_interfaces, struct registered_if, entry)
1162 if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid))
1164 if (!--rif->refs)
1166 RpcServerUnregisterIf((RPC_IF_HANDLE)&rif->If, NULL, TRUE);
1167 list_remove(&rif->entry);
1168 HeapFree(GetProcessHeap(), 0, rif);
1170 break;
1173 LeaveCriticalSection(&csRegIf);
1176 /* make the apartment reachable by other threads and processes and create the
1177 * IRemUnknown object */
1178 void RPC_StartRemoting(struct apartment *apt)
1180 if (!InterlockedExchange(&apt->remoting_started, TRUE))
1182 WCHAR endpoint[200];
1183 RPC_STATUS status;
1185 get_rpc_endpoint(endpoint, &apt->oxid);
1187 status = RpcServerUseProtseqEpW(
1188 wszRpcTransport,
1189 RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
1190 endpoint,
1191 NULL);
1192 if (status != RPC_S_OK)
1193 ERR("Couldn't register endpoint %s\n", debugstr_w(endpoint));
1195 /* FIXME: move remote unknown exporting into this function */
1197 start_apartment_remote_unknown();
1201 static HRESULT create_server(REFCLSID rclsid)
1203 static const WCHAR wszLocalServer32[] = { 'L','o','c','a','l','S','e','r','v','e','r','3','2',0 };
1204 static const WCHAR embedding[] = { ' ', '-','E','m','b','e','d','d','i','n','g',0 };
1205 HKEY key;
1206 HRESULT hres;
1207 WCHAR command[MAX_PATH+sizeof(embedding)/sizeof(WCHAR)];
1208 DWORD size = (MAX_PATH+1) * sizeof(WCHAR);
1209 STARTUPINFOW sinfo;
1210 PROCESS_INFORMATION pinfo;
1212 hres = COM_OpenKeyForCLSID(rclsid, wszLocalServer32, KEY_READ, &key);
1213 if (FAILED(hres)) {
1214 ERR("class %s not registered\n", debugstr_guid(rclsid));
1215 return hres;
1218 hres = RegQueryValueExW(key, NULL, NULL, NULL, (LPBYTE)command, &size);
1219 RegCloseKey(key);
1220 if (hres) {
1221 WARN("No default value for LocalServer32 key\n");
1222 return REGDB_E_CLASSNOTREG; /* FIXME: check retval */
1225 memset(&sinfo,0,sizeof(sinfo));
1226 sinfo.cb = sizeof(sinfo);
1228 /* EXE servers are started with the -Embedding switch. */
1230 strcatW(command, embedding);
1232 TRACE("activating local server %s for %s\n", debugstr_w(command), debugstr_guid(rclsid));
1234 /* FIXME: Win2003 supports a ServerExecutable value that is passed into
1235 * CreateProcess */
1236 if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo)) {
1237 WARN("failed to run local server %s\n", debugstr_w(command));
1238 return HRESULT_FROM_WIN32(GetLastError());
1240 CloseHandle(pinfo.hProcess);
1241 CloseHandle(pinfo.hThread);
1243 return S_OK;
1247 * start_local_service() - start a service given its name and parameters
1249 static DWORD start_local_service(LPCWSTR name, DWORD num, LPCWSTR *params)
1251 SC_HANDLE handle, hsvc;
1252 DWORD r = ERROR_FUNCTION_FAILED;
1254 TRACE("Starting service %s %d params\n", debugstr_w(name), num);
1256 handle = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
1257 if (!handle)
1258 return r;
1259 hsvc = OpenServiceW(handle, name, SERVICE_START);
1260 if (hsvc)
1262 if(StartServiceW(hsvc, num, params))
1263 r = ERROR_SUCCESS;
1264 else
1265 r = GetLastError();
1266 if (r == ERROR_SERVICE_ALREADY_RUNNING)
1267 r = ERROR_SUCCESS;
1268 CloseServiceHandle(hsvc);
1270 else
1271 r = GetLastError();
1272 CloseServiceHandle(handle);
1274 TRACE("StartService returned error %d (%s)\n", r, (r == ERROR_SUCCESS) ? "ok":"failed");
1276 return r;
1280 * create_local_service() - start a COM server in a service
1282 * To start a Local Service, we read the AppID value under
1283 * the class's CLSID key, then open the HKCR\\AppId key specified
1284 * there and check for a LocalService value.
1286 * Note: Local Services are not supported under Windows 9x
1288 static HRESULT create_local_service(REFCLSID rclsid)
1290 HRESULT hres;
1291 WCHAR buf[CHARS_IN_GUID];
1292 static const WCHAR szLocalService[] = { 'L','o','c','a','l','S','e','r','v','i','c','e',0 };
1293 static const WCHAR szServiceParams[] = {'S','e','r','v','i','c','e','P','a','r','a','m','s',0};
1294 HKEY hkey;
1295 LONG r;
1296 DWORD type, sz;
1298 TRACE("Attempting to start Local service for %s\n", debugstr_guid(rclsid));
1300 hres = COM_OpenKeyForAppIdFromCLSID(rclsid, KEY_READ, &hkey);
1301 if (FAILED(hres))
1302 return hres;
1304 /* read the LocalService and ServiceParameters values from the AppID key */
1305 sz = sizeof buf;
1306 r = RegQueryValueExW(hkey, szLocalService, NULL, &type, (LPBYTE)buf, &sz);
1307 if (r==ERROR_SUCCESS && type==REG_SZ)
1309 DWORD num_args = 0;
1310 LPWSTR args[1] = { NULL };
1313 * FIXME: I'm not really sure how to deal with the service parameters.
1314 * I suspect that the string returned from RegQueryValueExW
1315 * should be split into a number of arguments by spaces.
1316 * It would make more sense if ServiceParams contained a
1317 * REG_MULTI_SZ here, but it's a REG_SZ for the services
1318 * that I'm interested in for the moment.
1320 r = RegQueryValueExW(hkey, szServiceParams, NULL, &type, NULL, &sz);
1321 if (r == ERROR_SUCCESS && type == REG_SZ && sz)
1323 args[0] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz);
1324 num_args++;
1325 RegQueryValueExW(hkey, szServiceParams, NULL, &type, (LPBYTE)args[0], &sz);
1327 r = start_local_service(buf, num_args, (LPCWSTR *)args);
1328 if (r != ERROR_SUCCESS)
1329 hres = REGDB_E_CLASSNOTREG; /* FIXME: check retval */
1330 HeapFree(GetProcessHeap(),0,args[0]);
1332 else
1334 WARN("No LocalService value\n");
1335 hres = REGDB_E_CLASSNOTREG; /* FIXME: check retval */
1337 RegCloseKey(hkey);
1339 return hres;
1343 static void get_localserver_pipe_name(WCHAR *pipefn, REFCLSID rclsid)
1345 static const WCHAR wszPipeRef[] = {'\\','\\','.','\\','p','i','p','e','\\',0};
1346 strcpyW(pipefn, wszPipeRef);
1347 StringFromGUID2(rclsid, pipefn + sizeof(wszPipeRef)/sizeof(wszPipeRef[0]) - 1, CHARS_IN_GUID);
1350 /* FIXME: should call to rpcss instead */
1351 HRESULT RPC_GetLocalClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
1353 HRESULT hres;
1354 HANDLE hPipe;
1355 WCHAR pipefn[100];
1356 DWORD res, bufferlen;
1357 char marshalbuffer[200];
1358 IStream *pStm;
1359 LARGE_INTEGER seekto;
1360 ULARGE_INTEGER newpos;
1361 int tries = 0;
1363 static const int MAXTRIES = 30; /* 30 seconds */
1365 TRACE("rclsid=%s, iid=%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1367 get_localserver_pipe_name(pipefn, rclsid);
1369 while (tries++ < MAXTRIES) {
1370 TRACE("waiting for %s\n", debugstr_w(pipefn));
1372 WaitNamedPipeW( pipefn, NMPWAIT_WAIT_FOREVER );
1373 hPipe = CreateFileW(pipefn, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1374 if (hPipe == INVALID_HANDLE_VALUE) {
1375 if (tries == 1) {
1376 if ( (hres = create_local_service(rclsid)) &&
1377 (hres = create_server(rclsid)) )
1378 return hres;
1379 Sleep(1000);
1380 } else {
1381 WARN("Connecting to %s, no response yet, retrying: le is %x\n", debugstr_w(pipefn), GetLastError());
1382 Sleep(1000);
1384 continue;
1386 bufferlen = 0;
1387 if (!ReadFile(hPipe,marshalbuffer,sizeof(marshalbuffer),&bufferlen,NULL)) {
1388 FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid));
1389 Sleep(1000);
1390 continue;
1392 TRACE("read marshal id from pipe\n");
1393 CloseHandle(hPipe);
1394 break;
1397 if (tries >= MAXTRIES)
1398 return E_NOINTERFACE;
1400 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
1401 if (hres) return hres;
1402 hres = IStream_Write(pStm,marshalbuffer,bufferlen,&res);
1403 if (hres) goto out;
1404 seekto.u.LowPart = 0;seekto.u.HighPart = 0;
1405 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
1407 TRACE("unmarshalling classfactory\n");
1408 hres = CoUnmarshalInterface(pStm,&IID_IClassFactory,ppv);
1409 out:
1410 IStream_Release(pStm);
1411 return hres;
1415 struct local_server_params
1417 CLSID clsid;
1418 IStream *stream;
1419 HANDLE ready_event;
1422 /* FIXME: should call to rpcss instead */
1423 static DWORD WINAPI local_server_thread(LPVOID param)
1425 struct local_server_params * lsp = (struct local_server_params *)param;
1426 HANDLE hPipe;
1427 WCHAR pipefn[100];
1428 HRESULT hres;
1429 IStream *pStm = lsp->stream;
1430 STATSTG ststg;
1431 unsigned char *buffer;
1432 int buflen;
1433 LARGE_INTEGER seekto;
1434 ULARGE_INTEGER newpos;
1435 ULONG res;
1437 TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid));
1439 get_localserver_pipe_name(pipefn, &lsp->clsid);
1441 hPipe = CreateNamedPipeW( pipefn, PIPE_ACCESS_DUPLEX,
1442 PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
1443 4096, 4096, 500 /* 0.5 second timeout */, NULL );
1445 SetEvent(lsp->ready_event);
1447 HeapFree(GetProcessHeap(), 0, lsp);
1449 if (hPipe == INVALID_HANDLE_VALUE)
1451 FIXME("pipe creation failed for %s, le is %d\n", debugstr_w(pipefn), GetLastError());
1452 return 1;
1455 while (1) {
1456 if (!ConnectNamedPipe(hPipe,NULL) && GetLastError() != ERROR_PIPE_CONNECTED) {
1457 ERR("Failure during ConnectNamedPipe %d, ABORT!\n",GetLastError());
1458 break;
1461 TRACE("marshalling IClassFactory to client\n");
1463 hres = IStream_Stat(pStm,&ststg,0);
1464 if (hres) return hres;
1466 seekto.u.LowPart = 0;
1467 seekto.u.HighPart = 0;
1468 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
1469 if (hres) {
1470 FIXME("IStream_Seek failed, %x\n",hres);
1471 return hres;
1474 buflen = ststg.cbSize.u.LowPart;
1475 buffer = HeapAlloc(GetProcessHeap(),0,buflen);
1477 hres = IStream_Read(pStm,buffer,buflen,&res);
1478 if (hres) {
1479 FIXME("Stream Read failed, %x\n",hres);
1480 HeapFree(GetProcessHeap(),0,buffer);
1481 return hres;
1484 WriteFile(hPipe,buffer,buflen,&res,NULL);
1485 HeapFree(GetProcessHeap(),0,buffer);
1487 FlushFileBuffers(hPipe);
1488 DisconnectNamedPipe(hPipe);
1490 TRACE("done marshalling IClassFactory\n");
1492 CloseHandle(hPipe);
1493 IStream_Release(pStm);
1494 return 0;
1497 void RPC_StartLocalServer(REFCLSID clsid, IStream *stream)
1499 DWORD tid;
1500 HANDLE thread, ready_event;
1501 struct local_server_params *lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp));
1503 lsp->clsid = *clsid;
1504 lsp->stream = stream;
1505 IStream_AddRef(stream);
1506 lsp->ready_event = ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1508 thread = CreateThread(NULL, 0, local_server_thread, lsp, 0, &tid);
1509 CloseHandle(thread);
1510 /* FIXME: failure handling */
1512 WaitForSingleObject(ready_event, INFINITE);
1513 CloseHandle(ready_event);