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 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) */
130 RPC_BINDING_HANDLE binding_handle
;
131 ULONG prefix_data_len
;
132 SChannelHookCallInfo channel_hook_info
;
137 ULONG conformance
; /* NDR */
140 /* [size_is((size+7)&~7)] */ unsigned char data
[1];
143 struct channel_hook_entry
150 struct channel_hook_buffer_data
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;
168 *extension_count
= 0;
170 EnterCriticalSection(&csChannelHook
);
172 LIST_FOR_EACH_ENTRY(entry
, &channel_hooks
, struct channel_hook_entry
, entry
)
176 *data
= HeapAlloc(GetProcessHeap(), 0, *hook_count
* sizeof(struct channel_hook_buffer_data
));
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 */
195 total_size
+= FIELD_OFFSET(WIRE_ORPC_EXTENT
, data
[extension_size
]);
196 (*extension_count
)++;
202 LeaveCriticalSection(&csChannelHook
);
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
)
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 */
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
);
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
;
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
;
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
))
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
,
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
));
287 return E_OUTOFMEMORY
;
289 memcpy(&entry
->id
, rguid
, sizeof(entry
->id
));
291 IChannelHook_AddRef(hook
);
293 EnterCriticalSection(&csChannelHook
);
294 list_add_tail(&channel_hooks
, &entry
->entry
);
295 LeaveCriticalSection(&csChannelHook
);
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
)
316 if (IsEqualIID(riid
,&IID_IRpcChannelBuffer
) || IsEqualIID(riid
,&IID_IUnknown
))
318 *ppv
= (LPVOID
)iface
;
319 IUnknown_AddRef(iface
);
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
;
336 ref
= InterlockedDecrement(&This
->refs
);
340 HeapFree(GetProcessHeap(), 0, This
);
344 static ULONG WINAPI
ClientRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface
)
346 ClientRpcChannelBuffer
*This
= (ClientRpcChannelBuffer
*)iface
;
349 ref
= InterlockedDecrement(&This
->super
.refs
);
353 if (This
->event
) CloseHandle(This
->event
);
354 RpcBindingFree(&This
->bind
);
355 HeapFree(GetProcessHeap(), 0, This
);
359 static HRESULT WINAPI
ServerRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface
, RPCOLEMESSAGE
* olemsg
, REFIID riid
)
361 RpcChannelBuffer
*This
= (RpcChannelBuffer
*)iface
;
362 RPC_MESSAGE
*msg
= (RPC_MESSAGE
*)olemsg
;
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
;
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
));
401 return E_OUTOFMEMORY
;
403 message_state
= HeapAlloc(GetProcessHeap(), 0, sizeof(*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;
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
);
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
)
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
509 if (!event
) event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
514 static void ClientRpcChannelBuffer_ReleaseEventHandle(ClientRpcChannelBuffer
*This
, HANDLE event
)
516 if (InterlockedCompareExchangePointer(&This
->event
, event
, NULL
))
517 /* already a handle cached in This */
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
);
536 static inline HRESULT
ClientRpcChannelBuffer_IsCorrectApartment(ClientRpcChannelBuffer
*This
, APARTMENT
*apt
)
541 if (apartment_getoxid(apt
, &oxid
) != S_OK
)
543 if (This
->oxid
!= oxid
)
548 static HRESULT WINAPI
ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface
, RPCOLEMESSAGE
*olemsg
, ULONG
*pstatus
)
550 ClientRpcChannelBuffer
*This
= (ClientRpcChannelBuffer
*)iface
;
552 RPC_MESSAGE
*msg
= (RPC_MESSAGE
*)olemsg
;
555 struct dispatch_params
*params
;
556 APARTMENT
*apt
= NULL
;
558 struct message_state
*message_state
;
560 TRACE("(%p) iMethod=%d\n", olemsg
, olemsg
->iMethod
);
562 hr
= ClientRpcChannelBuffer_IsCorrectApartment(This
, COM_CurrentApt());
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
;
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
590 RpcBindingInqObject(message_state
->binding_handle
, &ipid
);
591 hr
= ipid_get_dispatch_params(&ipid
, &apt
, ¶ms
->stub
, ¶ms
->chan
,
592 ¶ms
->iid
, ¶ms
->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());
608 /* otherwise, we go via RPC runtime so the stub and channel aren't
610 IRpcStubBuffer_Release(params
->stub
);
612 IRpcChannelBuffer_Release(params
->chan
);
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());
630 if (apt
) apartment_release(apt
);
634 if (WaitForSingleObject(params
->handle
, 0))
635 hr
= CoWaitForMultipleHandles(0, INFINITE
, 1, ¶ms
->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
);
651 if (pstatus
) *pstatus
= status
;
653 TRACE("RPC call status: 0x%lx\n", status
);
654 if (status
== RPC_S_OK
)
656 else if (status
== RPC_S_CALL_FAILED
)
657 hr
= *(HRESULT
*)olemsg
->Buffer
;
659 hr
= HRESULT_FROM_WIN32(status
);
661 TRACE("-- 0x%08x\n", hr
);
666 static HRESULT WINAPI
ServerRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface
, RPCOLEMESSAGE
* olemsg
)
668 RPC_MESSAGE
*msg
= (RPC_MESSAGE
*)olemsg
;
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
;
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
;
727 static HRESULT WINAPI
ServerRpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface
, DWORD
* pdwDestContext
, void** ppvDestContext
)
729 FIXME("(%p,%p), stub!\n", pdwDestContext
, ppvDestContext
);
733 static HRESULT WINAPI
RpcChannelBuffer_IsConnected(LPRPCCHANNELBUFFER iface
)
736 /* native does nothing too */
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
;
771 RPC_BINDING_HANDLE bind
;
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(
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
));
812 RpcBindingFree(&bind
);
813 return E_OUTOFMEMORY
;
816 This
->super
.lpVtbl
= &ClientRpcChannelBufferVtbl
;
817 This
->super
.refs
= 1;
819 apartment_getoxid(COM_CurrentApt(), &This
->oxid
);
820 This
->dest_context
= dest_context
;
821 This
->dest_context_data
= dest_context_data
;
824 *chan
= (IRpcChannelBuffer
*)This
;
829 HRESULT
RPC_CreateServerChannel(IRpcChannelBuffer
**chan
)
831 RpcChannelBuffer
*This
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
833 return E_OUTOFMEMORY
;
835 This
->lpVtbl
= &ServerRpcChannelBufferVtbl
;
838 *chan
= (IRpcChannelBuffer
*)This
;
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
;
866 orpcthis
->extensions
= NULL
;
868 msg
->Buffer
= (char *)msg
->Buffer
+ sizeof(DWORD
);
870 if (orpcthis
->extensions
)
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
;
887 WIRE_ORPC_EXTENT
*wire_orpc_extent
;
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
;
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
;
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
)
950 message_state
= HeapAlloc(GetProcessHeap(), 0, sizeof(*message_state
));
953 params
->hr
= E_OUTOFMEMORY
;
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
)
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(),
989 TRACE("IMessageFilter_HandleInComingCall returned %d\n", handlecall
);
992 case SERVERCALL_REJECTED
:
993 params
->hr
= RPC_E_CALL_REJECTED
;
995 case SERVERCALL_RETRYLATER
:
996 #if 0 /* FIXME: handle retries on the client side before enabling this code */
997 params
->hr
= RPC_E_RETRY
;
1000 FIXME("retry call later not implemented\n");
1003 case SERVERCALL_ISHANDLED
:
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
;
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
;
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
, ¶ms
->stub
, ¶ms
->chan
,
1040 ¶ms
->iid
, ¶ms
->iface
);
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
;
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
);
1066 ERR("PostMessage failed with error %d\n", GetLastError());
1067 IRpcChannelBuffer_Release(params
->chan
);
1068 IRpcStubBuffer_Release(params
->stub
);
1070 CloseHandle(params
->handle
);
1074 BOOL joined
= FALSE
;
1075 if (!COM_CurrentInfo()->apt
)
1077 apartment_joinmta();
1080 RPC_ExecuteCall(params
);
1083 apartment_release(COM_CurrentInfo()->apt
);
1084 COM_CurrentInfo()->apt
= NULL
;
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
;
1105 TRACE("(%s)\n", debugstr_guid(riid
));
1107 EnterCriticalSection(&csRegIf
);
1108 LIST_FOR_EACH_ENTRY(rif
, ®istered_interfaces
, struct registered_if
, entry
)
1110 if (IsEqualGUID(&rif
->If
.InterfaceId
.SyntaxGUID
, riid
))
1119 TRACE("Creating new interface\n");
1121 rif
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*rif
));
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
,
1136 RPC_IF_OLE
| RPC_IF_AUTOLISTEN
,
1137 RPC_C_LISTEN_MAX_CALLS_DEFAULT
,
1139 if (status
== RPC_S_OK
)
1140 list_add_tail(®istered_interfaces
, &rif
->entry
);
1143 ERR("RpcServerRegisterIfEx failed with error %ld\n", status
);
1144 HeapFree(GetProcessHeap(), 0, rif
);
1145 hr
= HRESULT_FROM_WIN32(status
);
1151 LeaveCriticalSection(&csRegIf
);
1155 /* stub unregistration */
1156 void RPC_UnregisterInterface(REFIID riid
)
1158 struct registered_if
*rif
;
1159 EnterCriticalSection(&csRegIf
);
1160 LIST_FOR_EACH_ENTRY(rif
, ®istered_interfaces
, struct registered_if
, entry
)
1162 if (IsEqualGUID(&rif
->If
.InterfaceId
.SyntaxGUID
, riid
))
1166 RpcServerUnregisterIf((RPC_IF_HANDLE
)&rif
->If
, NULL
, TRUE
);
1167 list_remove(&rif
->entry
);
1168 HeapFree(GetProcessHeap(), 0, rif
);
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];
1185 get_rpc_endpoint(endpoint
, &apt
->oxid
);
1187 status
= RpcServerUseProtseqEpW(
1189 RPC_C_PROTSEQ_MAX_REQS_DEFAULT
,
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 };
1207 WCHAR command
[MAX_PATH
+sizeof(embedding
)/sizeof(WCHAR
)];
1208 DWORD size
= (MAX_PATH
+1) * sizeof(WCHAR
);
1210 PROCESS_INFORMATION pinfo
;
1212 hres
= COM_OpenKeyForCLSID(rclsid
, wszLocalServer32
, KEY_READ
, &key
);
1214 ERR("class %s not registered\n", debugstr_guid(rclsid
));
1218 hres
= RegQueryValueExW(key
, NULL
, NULL
, NULL
, (LPBYTE
)command
, &size
);
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
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
);
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
);
1259 hsvc
= OpenServiceW(handle
, name
, SERVICE_START
);
1262 if(StartServiceW(hsvc
, num
, params
))
1266 if (r
== ERROR_SERVICE_ALREADY_RUNNING
)
1268 CloseServiceHandle(hsvc
);
1272 CloseServiceHandle(handle
);
1274 TRACE("StartService returned error %d (%s)\n", r
, (r
== ERROR_SUCCESS
) ? "ok":"failed");
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
)
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};
1298 TRACE("Attempting to start Local service for %s\n", debugstr_guid(rclsid
));
1300 hres
= COM_OpenKeyForAppIdFromCLSID(rclsid
, KEY_READ
, &hkey
);
1304 /* read the LocalService and ServiceParameters values from the AppID key */
1306 r
= RegQueryValueExW(hkey
, szLocalService
, NULL
, &type
, (LPBYTE
)buf
, &sz
);
1307 if (r
==ERROR_SUCCESS
&& type
==REG_SZ
)
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
);
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]);
1334 WARN("No LocalService value\n");
1335 hres
= REGDB_E_CLASSNOTREG
; /* FIXME: check retval */
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
)
1356 DWORD res
, bufferlen
;
1357 char marshalbuffer
[200];
1359 LARGE_INTEGER seekto
;
1360 ULARGE_INTEGER newpos
;
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
) {
1376 if ( (hres
= create_local_service(rclsid
)) &&
1377 (hres
= create_server(rclsid
)) )
1381 WARN("Connecting to %s, no response yet, retrying: le is %x\n", debugstr_w(pipefn
), GetLastError());
1387 if (!ReadFile(hPipe
,marshalbuffer
,sizeof(marshalbuffer
),&bufferlen
,NULL
)) {
1388 FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid
));
1392 TRACE("read marshal id from pipe\n");
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
);
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
);
1410 IStream_Release(pStm
);
1415 struct local_server_params
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
;
1429 IStream
*pStm
= lsp
->stream
;
1431 unsigned char *buffer
;
1433 LARGE_INTEGER seekto
;
1434 ULARGE_INTEGER newpos
;
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());
1456 if (!ConnectNamedPipe(hPipe
,NULL
) && GetLastError() != ERROR_PIPE_CONNECTED
) {
1457 ERR("Failure during ConnectNamedPipe %d, ABORT!\n",GetLastError());
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
);
1470 FIXME("IStream_Seek failed, %x\n",hres
);
1474 buflen
= ststg
.cbSize
.u
.LowPart
;
1475 buffer
= HeapAlloc(GetProcessHeap(),0,buflen
);
1477 hres
= IStream_Read(pStm
,buffer
,buflen
,&res
);
1479 FIXME("Stream Read failed, %x\n",hres
);
1480 HeapFree(GetProcessHeap(),0,buffer
);
1484 WriteFile(hPipe
,buffer
,buflen
,&res
,NULL
);
1485 HeapFree(GetProcessHeap(),0,buffer
);
1487 FlushFileBuffers(hPipe
);
1488 DisconnectNamedPipe(hPipe
);
1490 TRACE("done marshalling IClassFactory\n");
1493 IStream_Release(pStm
);
1497 void RPC_StartLocalServer(REFCLSID clsid
, IStream
*stream
)
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
);