Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenrpc.c
Go to the documentation of this file.
00001 /* 00002 * RPC Manager 00003 * 00004 * Copyright 2001 Ove Kåven, TransGaming Technologies 00005 * Copyright 2002 Marcus Meissner 00006 * Copyright 2005 Mike Hearn, Rob Shearman for CodeWeavers 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00021 */ 00022 00023 #include "config.h" 00024 #include "wine/port.h" 00025 00026 #include <stdarg.h> 00027 #include <string.h> 00028 00029 #define COBJMACROS 00030 #define NONAMELESSUNION 00031 #define NONAMELESSSTRUCT 00032 00033 #include "windef.h" 00034 #include "winbase.h" 00035 #include "winuser.h" 00036 #include "winsvc.h" 00037 #include "objbase.h" 00038 #include "ole2.h" 00039 #include "rpc.h" 00040 #include "winerror.h" 00041 #include "winreg.h" 00042 #include "wine/unicode.h" 00043 00044 #include "compobj_private.h" 00045 00046 #include "wine/debug.h" 00047 00048 WINE_DEFAULT_DEBUG_CHANNEL(ole); 00049 00050 static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg); 00051 00052 /* we only use one function to dispatch calls for all methods - we use the 00053 * RPC_IF_OLE flag to tell the RPC runtime that this is the case */ 00054 static RPC_DISPATCH_FUNCTION rpc_dispatch_table[1] = { dispatch_rpc }; /* (RO) */ 00055 static RPC_DISPATCH_TABLE rpc_dispatch = { 1, rpc_dispatch_table }; /* (RO) */ 00056 00057 static struct list registered_interfaces = LIST_INIT(registered_interfaces); /* (CS csRegIf) */ 00058 static CRITICAL_SECTION csRegIf; 00059 static CRITICAL_SECTION_DEBUG csRegIf_debug = 00060 { 00061 0, 0, &csRegIf, 00062 { &csRegIf_debug.ProcessLocksList, &csRegIf_debug.ProcessLocksList }, 00063 0, 0, { (DWORD_PTR)(__FILE__ ": dcom registered server interfaces") } 00064 }; 00065 static CRITICAL_SECTION csRegIf = { &csRegIf_debug, -1, 0, 0, 0, 0 }; 00066 00067 static struct list channel_hooks = LIST_INIT(channel_hooks); /* (CS csChannelHook) */ 00068 static CRITICAL_SECTION csChannelHook; 00069 static CRITICAL_SECTION_DEBUG csChannelHook_debug = 00070 { 00071 0, 0, &csChannelHook, 00072 { &csChannelHook_debug.ProcessLocksList, &csChannelHook_debug.ProcessLocksList }, 00073 0, 0, { (DWORD_PTR)(__FILE__ ": channel hooks") } 00074 }; 00075 static CRITICAL_SECTION csChannelHook = { &csChannelHook_debug, -1, 0, 0, 0, 0 }; 00076 00077 static WCHAR wszRpcTransport[] = {'n','c','a','l','r','p','c',0}; 00078 00079 00080 struct registered_if 00081 { 00082 struct list entry; 00083 DWORD refs; /* ref count */ 00084 RPC_SERVER_INTERFACE If; /* interface registered with the RPC runtime */ 00085 }; 00086 00087 /* get the pipe endpoint specified of the specified apartment */ 00088 static inline void get_rpc_endpoint(LPWSTR endpoint, const OXID *oxid) 00089 { 00090 /* FIXME: should get endpoint from rpcss */ 00091 static const WCHAR wszEndpointFormat[] = {'\\','p','i','p','e','\\','O','L','E','_','%','0','8','l','x','%','0','8','l','x',0}; 00092 wsprintfW(endpoint, wszEndpointFormat, (DWORD)(*oxid >> 32),(DWORD)*oxid); 00093 } 00094 00095 typedef struct 00096 { 00097 const IRpcChannelBufferVtbl *lpVtbl; 00098 LONG refs; 00099 } RpcChannelBuffer; 00100 00101 typedef struct 00102 { 00103 RpcChannelBuffer super; /* superclass */ 00104 00105 RPC_BINDING_HANDLE bind; /* handle to the remote server */ 00106 OXID oxid; /* apartment in which the channel is valid */ 00107 DWORD server_pid; /* id of server process */ 00108 DWORD dest_context; /* returned from GetDestCtx */ 00109 LPVOID dest_context_data; /* returned from GetDestCtx */ 00110 HANDLE event; /* cached event handle */ 00111 } ClientRpcChannelBuffer; 00112 00113 struct dispatch_params 00114 { 00115 RPCOLEMESSAGE *msg; /* message */ 00116 IRpcStubBuffer *stub; /* stub buffer, if applicable */ 00117 IRpcChannelBuffer *chan; /* server channel buffer, if applicable */ 00118 IID iid; /* ID of interface being called */ 00119 IUnknown *iface; /* interface being called */ 00120 HANDLE handle; /* handle that will become signaled when call finishes */ 00121 BOOL bypass_rpcrt; /* bypass RPC runtime? */ 00122 RPC_STATUS status; /* status (out) */ 00123 HRESULT hr; /* hresult (out) */ 00124 }; 00125 00126 struct message_state 00127 { 00128 RPC_BINDING_HANDLE binding_handle; 00129 ULONG prefix_data_len; 00130 SChannelHookCallInfo channel_hook_info; 00131 BOOL bypass_rpcrt; 00132 00133 /* client only */ 00134 HWND target_hwnd; 00135 DWORD target_tid; 00136 struct dispatch_params params; 00137 }; 00138 00139 typedef struct 00140 { 00141 ULONG conformance; /* NDR */ 00142 GUID id; 00143 ULONG size; 00144 /* [size_is((size+7)&~7)] */ unsigned char data[1]; 00145 } WIRE_ORPC_EXTENT; 00146 00147 typedef struct 00148 { 00149 ULONG size; 00150 ULONG reserved; 00151 unsigned char extent[1]; 00152 } WIRE_ORPC_EXTENT_ARRAY; 00153 00154 typedef struct 00155 { 00156 ULONG version; 00157 ULONG flags; 00158 ULONG reserved1; 00159 GUID cid; 00160 unsigned char extensions[1]; 00161 } WIRE_ORPCTHIS; 00162 00163 typedef struct 00164 { 00165 ULONG flags; 00166 unsigned char extensions[1]; 00167 } WIRE_ORPCTHAT; 00168 00169 struct channel_hook_entry 00170 { 00171 struct list entry; 00172 GUID id; 00173 IChannelHook *hook; 00174 }; 00175 00176 struct channel_hook_buffer_data 00177 { 00178 GUID id; 00179 ULONG extension_size; 00180 }; 00181 00182 00183 static HRESULT unmarshal_ORPCTHAT(RPC_MESSAGE *msg, ORPCTHAT *orpcthat, 00184 ORPC_EXTENT_ARRAY *orpc_ext_array, WIRE_ORPC_EXTENT **first_wire_orpc_extent); 00185 00186 /* Channel Hook Functions */ 00187 00188 static ULONG ChannelHooks_ClientGetSize(SChannelHookCallInfo *info, 00189 struct channel_hook_buffer_data **data, unsigned int *hook_count, 00190 ULONG *extension_count) 00191 { 00192 struct channel_hook_entry *entry; 00193 ULONG total_size = 0; 00194 unsigned int hook_index = 0; 00195 00196 *hook_count = 0; 00197 *extension_count = 0; 00198 00199 EnterCriticalSection(&csChannelHook); 00200 00201 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry) 00202 (*hook_count)++; 00203 00204 if (*hook_count) 00205 *data = HeapAlloc(GetProcessHeap(), 0, *hook_count * sizeof(struct channel_hook_buffer_data)); 00206 else 00207 *data = NULL; 00208 00209 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry) 00210 { 00211 ULONG extension_size = 0; 00212 00213 IChannelHook_ClientGetSize(entry->hook, &entry->id, &info->iid, &extension_size); 00214 00215 TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size); 00216 00217 extension_size = (extension_size+7)&~7; 00218 (*data)[hook_index].id = entry->id; 00219 (*data)[hook_index].extension_size = extension_size; 00220 00221 /* an extension is only put onto the wire if it has data to write */ 00222 if (extension_size) 00223 { 00224 total_size += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[extension_size]); 00225 (*extension_count)++; 00226 } 00227 00228 hook_index++; 00229 } 00230 00231 LeaveCriticalSection(&csChannelHook); 00232 00233 return total_size; 00234 } 00235 00236 static unsigned char * ChannelHooks_ClientFillBuffer(SChannelHookCallInfo *info, 00237 unsigned char *buffer, struct channel_hook_buffer_data *data, 00238 unsigned int hook_count) 00239 { 00240 struct channel_hook_entry *entry; 00241 00242 EnterCriticalSection(&csChannelHook); 00243 00244 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry) 00245 { 00246 unsigned int i; 00247 ULONG extension_size = 0; 00248 WIRE_ORPC_EXTENT *wire_orpc_extent = (WIRE_ORPC_EXTENT *)buffer; 00249 00250 for (i = 0; i < hook_count; i++) 00251 if (IsEqualGUID(&entry->id, &data[i].id)) 00252 extension_size = data[i].extension_size; 00253 00254 /* an extension is only put onto the wire if it has data to write */ 00255 if (!extension_size) 00256 continue; 00257 00258 IChannelHook_ClientFillBuffer(entry->hook, &entry->id, &info->iid, 00259 &extension_size, buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0])); 00260 00261 TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size); 00262 00263 /* FIXME: set unused portion of wire_orpc_extent->data to 0? */ 00264 00265 wire_orpc_extent->conformance = (extension_size+7)&~7; 00266 wire_orpc_extent->size = extension_size; 00267 wire_orpc_extent->id = entry->id; 00268 buffer += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[wire_orpc_extent->conformance]); 00269 } 00270 00271 LeaveCriticalSection(&csChannelHook); 00272 00273 return buffer; 00274 } 00275 00276 static void ChannelHooks_ServerNotify(SChannelHookCallInfo *info, 00277 DWORD lDataRep, WIRE_ORPC_EXTENT *first_wire_orpc_extent, 00278 ULONG extension_count) 00279 { 00280 struct channel_hook_entry *entry; 00281 ULONG i; 00282 00283 EnterCriticalSection(&csChannelHook); 00284 00285 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry) 00286 { 00287 WIRE_ORPC_EXTENT *wire_orpc_extent; 00288 for (i = 0, wire_orpc_extent = first_wire_orpc_extent; 00289 i < extension_count; 00290 i++, wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance]) 00291 { 00292 if (IsEqualGUID(&entry->id, &wire_orpc_extent->id)) 00293 break; 00294 } 00295 if (i == extension_count) wire_orpc_extent = NULL; 00296 00297 IChannelHook_ServerNotify(entry->hook, &entry->id, &info->iid, 00298 wire_orpc_extent ? wire_orpc_extent->size : 0, 00299 wire_orpc_extent ? wire_orpc_extent->data : NULL, 00300 lDataRep); 00301 } 00302 00303 LeaveCriticalSection(&csChannelHook); 00304 } 00305 00306 static ULONG ChannelHooks_ServerGetSize(SChannelHookCallInfo *info, 00307 struct channel_hook_buffer_data **data, unsigned int *hook_count, 00308 ULONG *extension_count) 00309 { 00310 struct channel_hook_entry *entry; 00311 ULONG total_size = 0; 00312 unsigned int hook_index = 0; 00313 00314 *hook_count = 0; 00315 *extension_count = 0; 00316 00317 EnterCriticalSection(&csChannelHook); 00318 00319 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry) 00320 (*hook_count)++; 00321 00322 if (*hook_count) 00323 *data = HeapAlloc(GetProcessHeap(), 0, *hook_count * sizeof(struct channel_hook_buffer_data)); 00324 else 00325 *data = NULL; 00326 00327 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry) 00328 { 00329 ULONG extension_size = 0; 00330 00331 IChannelHook_ServerGetSize(entry->hook, &entry->id, &info->iid, S_OK, 00332 &extension_size); 00333 00334 TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size); 00335 00336 extension_size = (extension_size+7)&~7; 00337 (*data)[hook_index].id = entry->id; 00338 (*data)[hook_index].extension_size = extension_size; 00339 00340 /* an extension is only put onto the wire if it has data to write */ 00341 if (extension_size) 00342 { 00343 total_size += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[extension_size]); 00344 (*extension_count)++; 00345 } 00346 00347 hook_index++; 00348 } 00349 00350 LeaveCriticalSection(&csChannelHook); 00351 00352 return total_size; 00353 } 00354 00355 static unsigned char * ChannelHooks_ServerFillBuffer(SChannelHookCallInfo *info, 00356 unsigned char *buffer, struct channel_hook_buffer_data *data, 00357 unsigned int hook_count) 00358 { 00359 struct channel_hook_entry *entry; 00360 00361 EnterCriticalSection(&csChannelHook); 00362 00363 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry) 00364 { 00365 unsigned int i; 00366 ULONG extension_size = 0; 00367 WIRE_ORPC_EXTENT *wire_orpc_extent = (WIRE_ORPC_EXTENT *)buffer; 00368 00369 for (i = 0; i < hook_count; i++) 00370 if (IsEqualGUID(&entry->id, &data[i].id)) 00371 extension_size = data[i].extension_size; 00372 00373 /* an extension is only put onto the wire if it has data to write */ 00374 if (!extension_size) 00375 continue; 00376 00377 IChannelHook_ServerFillBuffer(entry->hook, &entry->id, &info->iid, 00378 &extension_size, buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]), 00379 S_OK); 00380 00381 TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size); 00382 00383 /* FIXME: set unused portion of wire_orpc_extent->data to 0? */ 00384 00385 wire_orpc_extent->conformance = (extension_size+7)&~7; 00386 wire_orpc_extent->size = extension_size; 00387 wire_orpc_extent->id = entry->id; 00388 buffer += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[wire_orpc_extent->conformance]); 00389 } 00390 00391 LeaveCriticalSection(&csChannelHook); 00392 00393 return buffer; 00394 } 00395 00396 static void ChannelHooks_ClientNotify(SChannelHookCallInfo *info, 00397 DWORD lDataRep, WIRE_ORPC_EXTENT *first_wire_orpc_extent, 00398 ULONG extension_count, HRESULT hrFault) 00399 { 00400 struct channel_hook_entry *entry; 00401 ULONG i; 00402 00403 EnterCriticalSection(&csChannelHook); 00404 00405 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry) 00406 { 00407 WIRE_ORPC_EXTENT *wire_orpc_extent; 00408 for (i = 0, wire_orpc_extent = first_wire_orpc_extent; 00409 i < extension_count; 00410 i++, wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance]) 00411 { 00412 if (IsEqualGUID(&entry->id, &wire_orpc_extent->id)) 00413 break; 00414 } 00415 if (i == extension_count) wire_orpc_extent = NULL; 00416 00417 IChannelHook_ClientNotify(entry->hook, &entry->id, &info->iid, 00418 wire_orpc_extent ? wire_orpc_extent->size : 0, 00419 wire_orpc_extent ? wire_orpc_extent->data : NULL, 00420 lDataRep, hrFault); 00421 } 00422 00423 LeaveCriticalSection(&csChannelHook); 00424 } 00425 00426 HRESULT RPC_RegisterChannelHook(REFGUID rguid, IChannelHook *hook) 00427 { 00428 struct channel_hook_entry *entry; 00429 00430 TRACE("(%s, %p)\n", debugstr_guid(rguid), hook); 00431 00432 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry)); 00433 if (!entry) 00434 return E_OUTOFMEMORY; 00435 00436 entry->id = *rguid; 00437 entry->hook = hook; 00438 IChannelHook_AddRef(hook); 00439 00440 EnterCriticalSection(&csChannelHook); 00441 list_add_tail(&channel_hooks, &entry->entry); 00442 LeaveCriticalSection(&csChannelHook); 00443 00444 return S_OK; 00445 } 00446 00447 void RPC_UnregisterAllChannelHooks(void) 00448 { 00449 struct channel_hook_entry *cursor; 00450 struct channel_hook_entry *cursor2; 00451 00452 EnterCriticalSection(&csChannelHook); 00453 LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &channel_hooks, struct channel_hook_entry, entry) 00454 HeapFree(GetProcessHeap(), 0, cursor); 00455 LeaveCriticalSection(&csChannelHook); 00456 DeleteCriticalSection(&csChannelHook); 00457 DeleteCriticalSection(&csRegIf); 00458 } 00459 00460 /* RPC Channel Buffer Functions */ 00461 00462 static HRESULT WINAPI RpcChannelBuffer_QueryInterface(LPRPCCHANNELBUFFER iface, REFIID riid, LPVOID *ppv) 00463 { 00464 *ppv = NULL; 00465 if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown)) 00466 { 00467 *ppv = iface; 00468 IUnknown_AddRef(iface); 00469 return S_OK; 00470 } 00471 return E_NOINTERFACE; 00472 } 00473 00474 static ULONG WINAPI RpcChannelBuffer_AddRef(LPRPCCHANNELBUFFER iface) 00475 { 00476 RpcChannelBuffer *This = (RpcChannelBuffer *)iface; 00477 return InterlockedIncrement(&This->refs); 00478 } 00479 00480 static ULONG WINAPI ServerRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface) 00481 { 00482 RpcChannelBuffer *This = (RpcChannelBuffer *)iface; 00483 ULONG ref; 00484 00485 ref = InterlockedDecrement(&This->refs); 00486 if (ref) 00487 return ref; 00488 00489 HeapFree(GetProcessHeap(), 0, This); 00490 return 0; 00491 } 00492 00493 static ULONG WINAPI ClientRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface) 00494 { 00495 ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface; 00496 ULONG ref; 00497 00498 ref = InterlockedDecrement(&This->super.refs); 00499 if (ref) 00500 return ref; 00501 00502 if (This->event) CloseHandle(This->event); 00503 RpcBindingFree(&This->bind); 00504 HeapFree(GetProcessHeap(), 0, This); 00505 return 0; 00506 } 00507 00508 static HRESULT WINAPI ServerRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid) 00509 { 00510 RpcChannelBuffer *This = (RpcChannelBuffer *)iface; 00511 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; 00512 RPC_STATUS status; 00513 ORPCTHAT *orpcthat; 00514 struct message_state *message_state; 00515 ULONG extensions_size; 00516 struct channel_hook_buffer_data *channel_hook_data; 00517 unsigned int channel_hook_count; 00518 ULONG extension_count; 00519 00520 TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid)); 00521 00522 message_state = msg->Handle; 00523 /* restore the binding handle and the real start of data */ 00524 msg->Handle = message_state->binding_handle; 00525 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len; 00526 00527 extensions_size = ChannelHooks_ServerGetSize(&message_state->channel_hook_info, 00528 &channel_hook_data, &channel_hook_count, &extension_count); 00529 00530 msg->BufferLength += FIELD_OFFSET(WIRE_ORPCTHAT, extensions) + sizeof(DWORD); 00531 if (extensions_size) 00532 { 00533 msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent[2*sizeof(DWORD) + extensions_size]); 00534 if (extension_count & 1) 00535 msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]); 00536 } 00537 00538 if (message_state->bypass_rpcrt) 00539 { 00540 msg->Buffer = HeapAlloc(GetProcessHeap(), 0, msg->BufferLength); 00541 if (msg->Buffer) 00542 status = RPC_S_OK; 00543 else 00544 { 00545 HeapFree(GetProcessHeap(), 0, channel_hook_data); 00546 return E_OUTOFMEMORY; 00547 } 00548 } 00549 else 00550 status = I_RpcGetBuffer(msg); 00551 00552 orpcthat = msg->Buffer; 00553 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPCTHAT, extensions); 00554 00555 orpcthat->flags = ORPCF_NULL /* FIXME? */; 00556 00557 /* NDR representation of orpcthat->extensions */ 00558 *(DWORD *)msg->Buffer = extensions_size ? 1 : 0; 00559 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); 00560 00561 if (extensions_size) 00562 { 00563 WIRE_ORPC_EXTENT_ARRAY *orpc_extent_array = msg->Buffer; 00564 orpc_extent_array->size = extension_count; 00565 orpc_extent_array->reserved = 0; 00566 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent); 00567 /* NDR representation of orpc_extent_array->extent */ 00568 *(DWORD *)msg->Buffer = 1; 00569 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); 00570 /* NDR representation of [size_is] attribute of orpc_extent_array->extent */ 00571 *(DWORD *)msg->Buffer = (extension_count + 1) & ~1; 00572 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); 00573 00574 msg->Buffer = ChannelHooks_ServerFillBuffer(&message_state->channel_hook_info, 00575 msg->Buffer, channel_hook_data, channel_hook_count); 00576 00577 /* we must add a dummy extension if there is an odd extension 00578 * count to meet the contract specified by the size_is attribute */ 00579 if (extension_count & 1) 00580 { 00581 WIRE_ORPC_EXTENT *wire_orpc_extent = msg->Buffer; 00582 wire_orpc_extent->conformance = 0; 00583 wire_orpc_extent->id = GUID_NULL; 00584 wire_orpc_extent->size = 0; 00585 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]); 00586 } 00587 } 00588 00589 HeapFree(GetProcessHeap(), 0, channel_hook_data); 00590 00591 /* store the prefixed data length so that we can restore the real buffer 00592 * later */ 00593 message_state->prefix_data_len = (char *)msg->Buffer - (char *)orpcthat; 00594 msg->BufferLength -= message_state->prefix_data_len; 00595 /* save away the message state again */ 00596 msg->Handle = message_state; 00597 00598 TRACE("-- %d\n", status); 00599 00600 return HRESULT_FROM_WIN32(status); 00601 } 00602 00603 static HANDLE ClientRpcChannelBuffer_GetEventHandle(ClientRpcChannelBuffer *This) 00604 { 00605 HANDLE event = InterlockedExchangePointer(&This->event, NULL); 00606 00607 /* Note: must be auto-reset event so we can reuse it without a call 00608 * to ResetEvent */ 00609 if (!event) event = CreateEventW(NULL, FALSE, FALSE, NULL); 00610 00611 return event; 00612 } 00613 00614 static void ClientRpcChannelBuffer_ReleaseEventHandle(ClientRpcChannelBuffer *This, HANDLE event) 00615 { 00616 if (InterlockedCompareExchangePointer(&This->event, event, NULL)) 00617 /* already a handle cached in This */ 00618 CloseHandle(event); 00619 } 00620 00621 static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid) 00622 { 00623 ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface; 00624 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; 00625 RPC_CLIENT_INTERFACE *cif; 00626 RPC_STATUS status; 00627 ORPCTHIS *orpcthis; 00628 struct message_state *message_state; 00629 ULONG extensions_size; 00630 struct channel_hook_buffer_data *channel_hook_data; 00631 unsigned int channel_hook_count; 00632 ULONG extension_count; 00633 IPID ipid; 00634 HRESULT hr; 00635 APARTMENT *apt = NULL; 00636 00637 TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid)); 00638 00639 cif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_CLIENT_INTERFACE)); 00640 if (!cif) 00641 return E_OUTOFMEMORY; 00642 00643 message_state = HeapAlloc(GetProcessHeap(), 0, sizeof(*message_state)); 00644 if (!message_state) 00645 { 00646 HeapFree(GetProcessHeap(), 0, cif); 00647 return E_OUTOFMEMORY; 00648 } 00649 00650 cif->Length = sizeof(RPC_CLIENT_INTERFACE); 00651 /* RPC interface ID = COM interface ID */ 00652 cif->InterfaceId.SyntaxGUID = *riid; 00653 /* COM objects always have a version of 0.0 */ 00654 cif->InterfaceId.SyntaxVersion.MajorVersion = 0; 00655 cif->InterfaceId.SyntaxVersion.MinorVersion = 0; 00656 msg->Handle = This->bind; 00657 msg->RpcInterfaceInformation = cif; 00658 00659 message_state->prefix_data_len = 0; 00660 message_state->binding_handle = This->bind; 00661 00662 message_state->channel_hook_info.iid = *riid; 00663 message_state->channel_hook_info.cbSize = sizeof(message_state->channel_hook_info); 00664 message_state->channel_hook_info.uCausality = COM_CurrentCausalityId(); 00665 message_state->channel_hook_info.dwServerPid = This->server_pid; 00666 message_state->channel_hook_info.iMethod = msg->ProcNum; 00667 message_state->channel_hook_info.pObject = NULL; /* only present on server-side */ 00668 message_state->target_hwnd = NULL; 00669 message_state->target_tid = 0; 00670 memset(&message_state->params, 0, sizeof(message_state->params)); 00671 00672 extensions_size = ChannelHooks_ClientGetSize(&message_state->channel_hook_info, 00673 &channel_hook_data, &channel_hook_count, &extension_count); 00674 00675 msg->BufferLength += FIELD_OFFSET(WIRE_ORPCTHIS, extensions) + sizeof(DWORD); 00676 if (extensions_size) 00677 { 00678 msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent[2*sizeof(DWORD) + extensions_size]); 00679 if (extension_count & 1) 00680 msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]); 00681 } 00682 00683 RpcBindingInqObject(message_state->binding_handle, &ipid); 00684 hr = ipid_get_dispatch_params(&ipid, &apt, &message_state->params.stub, 00685 &message_state->params.chan, 00686 &message_state->params.iid, 00687 &message_state->params.iface); 00688 if (hr == S_OK) 00689 { 00690 /* stub, chan, iface and iid are unneeded in multi-threaded case as we go 00691 * via the RPC runtime */ 00692 if (apt->multi_threaded) 00693 { 00694 IRpcStubBuffer_Release(message_state->params.stub); 00695 message_state->params.stub = NULL; 00696 IRpcChannelBuffer_Release(message_state->params.chan); 00697 message_state->params.chan = NULL; 00698 message_state->params.iface = NULL; 00699 } 00700 else 00701 { 00702 message_state->params.bypass_rpcrt = TRUE; 00703 message_state->target_hwnd = apartment_getwindow(apt); 00704 message_state->target_tid = apt->tid; 00705 /* we assume later on that this being non-NULL is the indicator that 00706 * means call directly instead of going through RPC runtime */ 00707 if (!message_state->target_hwnd) 00708 ERR("window for apartment %s is NULL\n", wine_dbgstr_longlong(apt->oxid)); 00709 } 00710 } 00711 if (apt) apartment_release(apt); 00712 message_state->params.handle = ClientRpcChannelBuffer_GetEventHandle(This); 00713 /* Note: message_state->params.msg is initialised in 00714 * ClientRpcChannelBuffer_SendReceive */ 00715 00716 /* shortcut the RPC runtime */ 00717 if (message_state->target_hwnd) 00718 { 00719 msg->Buffer = HeapAlloc(GetProcessHeap(), 0, msg->BufferLength); 00720 if (msg->Buffer) 00721 status = RPC_S_OK; 00722 else 00723 status = ERROR_OUTOFMEMORY; 00724 } 00725 else 00726 status = I_RpcGetBuffer(msg); 00727 00728 msg->Handle = message_state; 00729 00730 if (status == RPC_S_OK) 00731 { 00732 orpcthis = msg->Buffer; 00733 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPCTHIS, extensions); 00734 00735 orpcthis->version.MajorVersion = COM_MAJOR_VERSION; 00736 orpcthis->version.MinorVersion = COM_MINOR_VERSION; 00737 orpcthis->flags = message_state->channel_hook_info.dwServerPid ? ORPCF_LOCAL : ORPCF_NULL; 00738 orpcthis->reserved1 = 0; 00739 orpcthis->cid = message_state->channel_hook_info.uCausality; 00740 00741 /* NDR representation of orpcthis->extensions */ 00742 *(DWORD *)msg->Buffer = extensions_size ? 1 : 0; 00743 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); 00744 00745 if (extensions_size) 00746 { 00747 ORPC_EXTENT_ARRAY *orpc_extent_array = msg->Buffer; 00748 orpc_extent_array->size = extension_count; 00749 orpc_extent_array->reserved = 0; 00750 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent); 00751 /* NDR representation of orpc_extent_array->extent */ 00752 *(DWORD *)msg->Buffer = 1; 00753 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); 00754 /* NDR representation of [size_is] attribute of orpc_extent_array->extent */ 00755 *(DWORD *)msg->Buffer = (extension_count + 1) & ~1; 00756 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); 00757 00758 msg->Buffer = ChannelHooks_ClientFillBuffer(&message_state->channel_hook_info, 00759 msg->Buffer, channel_hook_data, channel_hook_count); 00760 00761 /* we must add a dummy extension if there is an odd extension 00762 * count to meet the contract specified by the size_is attribute */ 00763 if (extension_count & 1) 00764 { 00765 WIRE_ORPC_EXTENT *wire_orpc_extent = msg->Buffer; 00766 wire_orpc_extent->conformance = 0; 00767 wire_orpc_extent->id = GUID_NULL; 00768 wire_orpc_extent->size = 0; 00769 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]); 00770 } 00771 } 00772 00773 /* store the prefixed data length so that we can restore the real buffer 00774 * pointer in ClientRpcChannelBuffer_SendReceive. */ 00775 message_state->prefix_data_len = (char *)msg->Buffer - (char *)orpcthis; 00776 msg->BufferLength -= message_state->prefix_data_len; 00777 } 00778 00779 HeapFree(GetProcessHeap(), 0, channel_hook_data); 00780 00781 TRACE("-- %d\n", status); 00782 00783 return HRESULT_FROM_WIN32(status); 00784 } 00785 00786 static HRESULT WINAPI ServerRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus) 00787 { 00788 FIXME("stub\n"); 00789 return E_NOTIMPL; 00790 } 00791 00792 /* this thread runs an outgoing RPC */ 00793 static DWORD WINAPI rpc_sendreceive_thread(LPVOID param) 00794 { 00795 struct dispatch_params *data = param; 00796 00797 /* Note: I_RpcSendReceive doesn't raise exceptions like the higher-level 00798 * RPC functions do */ 00799 data->status = I_RpcSendReceive((RPC_MESSAGE *)data->msg); 00800 00801 TRACE("completed with status 0x%x\n", data->status); 00802 00803 SetEvent(data->handle); 00804 00805 return 0; 00806 } 00807 00808 static inline HRESULT ClientRpcChannelBuffer_IsCorrectApartment(ClientRpcChannelBuffer *This, APARTMENT *apt) 00809 { 00810 OXID oxid; 00811 if (!apt) 00812 return S_FALSE; 00813 if (apartment_getoxid(apt, &oxid) != S_OK) 00814 return S_FALSE; 00815 if (This->oxid != oxid) 00816 return S_FALSE; 00817 return S_OK; 00818 } 00819 00820 static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus) 00821 { 00822 ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface; 00823 HRESULT hr; 00824 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; 00825 RPC_STATUS status; 00826 DWORD index; 00827 struct message_state *message_state; 00828 ORPCTHAT orpcthat; 00829 ORPC_EXTENT_ARRAY orpc_ext_array; 00830 WIRE_ORPC_EXTENT *first_wire_orpc_extent = NULL; 00831 HRESULT hrFault = S_OK; 00832 00833 TRACE("(%p) iMethod=%d\n", olemsg, olemsg->iMethod); 00834 00835 hr = ClientRpcChannelBuffer_IsCorrectApartment(This, COM_CurrentApt()); 00836 if (hr != S_OK) 00837 { 00838 ERR("called from wrong apartment, should have been 0x%s\n", 00839 wine_dbgstr_longlong(This->oxid)); 00840 return RPC_E_WRONG_THREAD; 00841 } 00842 /* This situation should be impossible in multi-threaded apartments, 00843 * because the calling thread isn't re-enterable. 00844 * Note: doing a COM call during the processing of a sent message is 00845 * only disallowed if a client call is already being waited for 00846 * completion */ 00847 if (!COM_CurrentApt()->multi_threaded && 00848 COM_CurrentInfo()->pending_call_count_client && 00849 InSendMessage()) 00850 { 00851 ERR("can't make an outgoing COM call in response to a sent message\n"); 00852 return RPC_E_CANTCALLOUT_ININPUTSYNCCALL; 00853 } 00854 00855 message_state = msg->Handle; 00856 /* restore the binding handle and the real start of data */ 00857 msg->Handle = message_state->binding_handle; 00858 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len; 00859 msg->BufferLength += message_state->prefix_data_len; 00860 00861 /* Note: this is an optimization in the Microsoft OLE runtime that we need 00862 * to copy, as shown by the test_no_couninitialize_client test. without 00863 * short-circuiting the RPC runtime in the case below, the test will 00864 * deadlock on the loader lock due to the RPC runtime needing to create 00865 * a thread to process the RPC when this function is called indirectly 00866 * from DllMain */ 00867 00868 message_state->params.msg = olemsg; 00869 if (message_state->params.bypass_rpcrt) 00870 { 00871 TRACE("Calling apartment thread 0x%08x...\n", message_state->target_tid); 00872 00873 msg->ProcNum &= ~RPC_FLAGS_VALID_BIT; 00874 00875 if (!PostMessageW(message_state->target_hwnd, DM_EXECUTERPC, 0, 00876 (LPARAM)&message_state->params)) 00877 { 00878 ERR("PostMessage failed with error %u\n", GetLastError()); 00879 00880 /* Note: message_state->params.iface doesn't have a reference and 00881 * so doesn't need to be released */ 00882 00883 hr = HRESULT_FROM_WIN32(GetLastError()); 00884 } 00885 } 00886 else 00887 { 00888 /* we use a separate thread here because we need to be able to 00889 * pump the message loop in the application thread: if we do not, 00890 * any windows created by this thread will hang and RPCs that try 00891 * and re-enter this STA from an incoming server thread will 00892 * deadlock. InstallShield is an example of that. 00893 */ 00894 if (!QueueUserWorkItem(rpc_sendreceive_thread, &message_state->params, WT_EXECUTEDEFAULT)) 00895 { 00896 ERR("QueueUserWorkItem failed with error %u\n", GetLastError()); 00897 hr = E_UNEXPECTED; 00898 } 00899 else 00900 hr = S_OK; 00901 } 00902 00903 if (hr == S_OK) 00904 { 00905 if (WaitForSingleObject(message_state->params.handle, 0)) 00906 { 00907 COM_CurrentInfo()->pending_call_count_client++; 00908 hr = CoWaitForMultipleHandles(0, INFINITE, 1, &message_state->params.handle, &index); 00909 COM_CurrentInfo()->pending_call_count_client--; 00910 } 00911 } 00912 ClientRpcChannelBuffer_ReleaseEventHandle(This, message_state->params.handle); 00913 00914 /* for WM shortcut, faults are returned in params->hr */ 00915 if (hr == S_OK) 00916 hrFault = message_state->params.hr; 00917 00918 status = message_state->params.status; 00919 00920 orpcthat.flags = ORPCF_NULL; 00921 orpcthat.extensions = NULL; 00922 00923 TRACE("RPC call status: 0x%x\n", status); 00924 if (status != RPC_S_OK) 00925 hr = HRESULT_FROM_WIN32(status); 00926 00927 TRACE("hrFault = 0x%08x\n", hrFault); 00928 00929 /* FIXME: this condition should be 00930 * "hr == S_OK && (!hrFault || msg->BufferLength > FIELD_OFFSET(ORPCTHAT, extensions) + 4)" 00931 * but we don't currently reset the message length for PostMessage 00932 * dispatched calls */ 00933 if (hr == S_OK && hrFault == S_OK) 00934 { 00935 HRESULT hr2; 00936 char *original_buffer = msg->Buffer; 00937 00938 /* handle ORPCTHAT and client extensions */ 00939 00940 hr2 = unmarshal_ORPCTHAT(msg, &orpcthat, &orpc_ext_array, &first_wire_orpc_extent); 00941 if (FAILED(hr2)) 00942 hr = hr2; 00943 00944 message_state->prefix_data_len = (char *)msg->Buffer - original_buffer; 00945 msg->BufferLength -= message_state->prefix_data_len; 00946 } 00947 else 00948 message_state->prefix_data_len = 0; 00949 00950 if (hr == S_OK) 00951 { 00952 ChannelHooks_ClientNotify(&message_state->channel_hook_info, 00953 msg->DataRepresentation, 00954 first_wire_orpc_extent, 00955 orpcthat.extensions && first_wire_orpc_extent ? orpcthat.extensions->size : 0, 00956 hrFault); 00957 } 00958 00959 /* save away the message state again */ 00960 msg->Handle = message_state; 00961 00962 if (pstatus) *pstatus = status; 00963 00964 if (hr == S_OK) 00965 hr = hrFault; 00966 00967 TRACE("-- 0x%08x\n", hr); 00968 00969 return hr; 00970 } 00971 00972 static HRESULT WINAPI ServerRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg) 00973 { 00974 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; 00975 RPC_STATUS status; 00976 struct message_state *message_state; 00977 00978 TRACE("(%p)\n", msg); 00979 00980 message_state = msg->Handle; 00981 /* restore the binding handle and the real start of data */ 00982 msg->Handle = message_state->binding_handle; 00983 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len; 00984 msg->BufferLength += message_state->prefix_data_len; 00985 message_state->prefix_data_len = 0; 00986 00987 if (message_state->bypass_rpcrt) 00988 { 00989 HeapFree(GetProcessHeap(), 0, msg->Buffer); 00990 status = RPC_S_OK; 00991 } 00992 else 00993 status = I_RpcFreeBuffer(msg); 00994 00995 msg->Handle = message_state; 00996 00997 TRACE("-- %d\n", status); 00998 00999 return HRESULT_FROM_WIN32(status); 01000 } 01001 01002 static HRESULT WINAPI ClientRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg) 01003 { 01004 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; 01005 RPC_STATUS status; 01006 struct message_state *message_state; 01007 01008 TRACE("(%p)\n", msg); 01009 01010 message_state = msg->Handle; 01011 /* restore the binding handle and the real start of data */ 01012 msg->Handle = message_state->binding_handle; 01013 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len; 01014 msg->BufferLength += message_state->prefix_data_len; 01015 01016 if (message_state->params.bypass_rpcrt) 01017 { 01018 HeapFree(GetProcessHeap(), 0, msg->Buffer); 01019 status = RPC_S_OK; 01020 } 01021 else 01022 status = I_RpcFreeBuffer(msg); 01023 01024 HeapFree(GetProcessHeap(), 0, msg->RpcInterfaceInformation); 01025 msg->RpcInterfaceInformation = NULL; 01026 01027 if (message_state->params.stub) 01028 IRpcStubBuffer_Release(message_state->params.stub); 01029 if (message_state->params.chan) 01030 IRpcChannelBuffer_Release(message_state->params.chan); 01031 HeapFree(GetProcessHeap(), 0, message_state); 01032 01033 TRACE("-- %d\n", status); 01034 01035 return HRESULT_FROM_WIN32(status); 01036 } 01037 01038 static HRESULT WINAPI ClientRpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext) 01039 { 01040 ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface; 01041 01042 TRACE("(%p,%p)\n", pdwDestContext, ppvDestContext); 01043 01044 *pdwDestContext = This->dest_context; 01045 *ppvDestContext = This->dest_context_data; 01046 01047 return S_OK; 01048 } 01049 01050 static HRESULT WINAPI ServerRpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext) 01051 { 01052 WARN("(%p,%p), stub!\n", pdwDestContext, ppvDestContext); 01053 01054 /* FIXME: implement this by storing the dwDestContext and pvDestContext 01055 * values passed into IMarshal_MarshalInterface and returning them here */ 01056 *pdwDestContext = MSHCTX_DIFFERENTMACHINE; 01057 *ppvDestContext = NULL; 01058 return S_OK; 01059 } 01060 01061 static HRESULT WINAPI RpcChannelBuffer_IsConnected(LPRPCCHANNELBUFFER iface) 01062 { 01063 TRACE("()\n"); 01064 /* native does nothing too */ 01065 return S_OK; 01066 } 01067 01068 static const IRpcChannelBufferVtbl ClientRpcChannelBufferVtbl = 01069 { 01070 RpcChannelBuffer_QueryInterface, 01071 RpcChannelBuffer_AddRef, 01072 ClientRpcChannelBuffer_Release, 01073 ClientRpcChannelBuffer_GetBuffer, 01074 ClientRpcChannelBuffer_SendReceive, 01075 ClientRpcChannelBuffer_FreeBuffer, 01076 ClientRpcChannelBuffer_GetDestCtx, 01077 RpcChannelBuffer_IsConnected 01078 }; 01079 01080 static const IRpcChannelBufferVtbl ServerRpcChannelBufferVtbl = 01081 { 01082 RpcChannelBuffer_QueryInterface, 01083 RpcChannelBuffer_AddRef, 01084 ServerRpcChannelBuffer_Release, 01085 ServerRpcChannelBuffer_GetBuffer, 01086 ServerRpcChannelBuffer_SendReceive, 01087 ServerRpcChannelBuffer_FreeBuffer, 01088 ServerRpcChannelBuffer_GetDestCtx, 01089 RpcChannelBuffer_IsConnected 01090 }; 01091 01092 /* returns a channel buffer for proxies */ 01093 HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, 01094 const OXID_INFO *oxid_info, 01095 DWORD dest_context, void *dest_context_data, 01096 IRpcChannelBuffer **chan) 01097 { 01098 ClientRpcChannelBuffer *This; 01099 WCHAR endpoint[200]; 01100 RPC_BINDING_HANDLE bind; 01101 RPC_STATUS status; 01102 LPWSTR string_binding; 01103 01104 /* FIXME: get the endpoint from oxid_info->psa instead */ 01105 get_rpc_endpoint(endpoint, oxid); 01106 01107 TRACE("proxy pipe: connecting to endpoint: %s\n", debugstr_w(endpoint)); 01108 01109 status = RpcStringBindingComposeW( 01110 NULL, 01111 wszRpcTransport, 01112 NULL, 01113 endpoint, 01114 NULL, 01115 &string_binding); 01116 01117 if (status == RPC_S_OK) 01118 { 01119 status = RpcBindingFromStringBindingW(string_binding, &bind); 01120 01121 if (status == RPC_S_OK) 01122 { 01123 IPID ipid2 = *ipid; /* why can't RpcBindingSetObject take a const? */ 01124 status = RpcBindingSetObject(bind, &ipid2); 01125 if (status != RPC_S_OK) 01126 RpcBindingFree(&bind); 01127 } 01128 01129 RpcStringFreeW(&string_binding); 01130 } 01131 01132 if (status != RPC_S_OK) 01133 { 01134 ERR("Couldn't get binding for endpoint %s, status = %d\n", debugstr_w(endpoint), status); 01135 return HRESULT_FROM_WIN32(status); 01136 } 01137 01138 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 01139 if (!This) 01140 { 01141 RpcBindingFree(&bind); 01142 return E_OUTOFMEMORY; 01143 } 01144 01145 This->super.lpVtbl = &ClientRpcChannelBufferVtbl; 01146 This->super.refs = 1; 01147 This->bind = bind; 01148 apartment_getoxid(COM_CurrentApt(), &This->oxid); 01149 This->server_pid = oxid_info->dwPid; 01150 This->dest_context = dest_context; 01151 This->dest_context_data = dest_context_data; 01152 This->event = NULL; 01153 01154 *chan = (IRpcChannelBuffer*)This; 01155 01156 return S_OK; 01157 } 01158 01159 HRESULT RPC_CreateServerChannel(IRpcChannelBuffer **chan) 01160 { 01161 RpcChannelBuffer *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 01162 if (!This) 01163 return E_OUTOFMEMORY; 01164 01165 This->lpVtbl = &ServerRpcChannelBufferVtbl; 01166 This->refs = 1; 01167 01168 *chan = (IRpcChannelBuffer*)This; 01169 01170 return S_OK; 01171 } 01172 01173 /* unmarshals ORPC_EXTENT_ARRAY according to NDR rules, but doesn't allocate 01174 * any memory */ 01175 static HRESULT unmarshal_ORPC_EXTENT_ARRAY(RPC_MESSAGE *msg, const char *end, 01176 ORPC_EXTENT_ARRAY *extensions, 01177 WIRE_ORPC_EXTENT **first_wire_orpc_extent) 01178 { 01179 DWORD pointer_id; 01180 DWORD i; 01181 01182 memcpy(extensions, msg->Buffer, FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent)); 01183 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent); 01184 01185 if ((const char *)msg->Buffer + 2 * sizeof(DWORD) > end) 01186 return RPC_E_INVALID_HEADER; 01187 01188 pointer_id = *(DWORD *)msg->Buffer; 01189 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); 01190 extensions->extent = NULL; 01191 01192 if (pointer_id) 01193 { 01194 WIRE_ORPC_EXTENT *wire_orpc_extent; 01195 01196 /* conformance */ 01197 if (*(DWORD *)msg->Buffer != ((extensions->size+1)&~1)) 01198 return RPC_S_INVALID_BOUND; 01199 01200 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); 01201 01202 /* arbitrary limit for security (don't know what native does) */ 01203 if (extensions->size > 256) 01204 { 01205 ERR("too many extensions: %d\n", extensions->size); 01206 return RPC_S_INVALID_BOUND; 01207 } 01208 01209 *first_wire_orpc_extent = wire_orpc_extent = msg->Buffer; 01210 for (i = 0; i < ((extensions->size+1)&~1); i++) 01211 { 01212 if ((const char *)&wire_orpc_extent->data[0] > end) 01213 return RPC_S_INVALID_BOUND; 01214 if (wire_orpc_extent->conformance != ((wire_orpc_extent->size+7)&~7)) 01215 return RPC_S_INVALID_BOUND; 01216 if ((const char *)&wire_orpc_extent->data[wire_orpc_extent->conformance] > end) 01217 return RPC_S_INVALID_BOUND; 01218 TRACE("size %u, guid %s\n", wire_orpc_extent->size, debugstr_guid(&wire_orpc_extent->id)); 01219 wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance]; 01220 } 01221 msg->Buffer = wire_orpc_extent; 01222 } 01223 01224 return S_OK; 01225 } 01226 01227 /* unmarshals ORPCTHIS according to NDR rules, but doesn't allocate any memory */ 01228 static HRESULT unmarshal_ORPCTHIS(RPC_MESSAGE *msg, ORPCTHIS *orpcthis, 01229 ORPC_EXTENT_ARRAY *orpc_ext_array, WIRE_ORPC_EXTENT **first_wire_orpc_extent) 01230 { 01231 const char *end = (char *)msg->Buffer + msg->BufferLength; 01232 01233 *first_wire_orpc_extent = NULL; 01234 01235 if (msg->BufferLength < FIELD_OFFSET(WIRE_ORPCTHIS, extensions) + sizeof(DWORD)) 01236 { 01237 ERR("invalid buffer length\n"); 01238 return RPC_E_INVALID_HEADER; 01239 } 01240 01241 memcpy(orpcthis, msg->Buffer, FIELD_OFFSET(WIRE_ORPCTHIS, extensions)); 01242 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPCTHIS, extensions); 01243 01244 if ((const char *)msg->Buffer + sizeof(DWORD) > end) 01245 return RPC_E_INVALID_HEADER; 01246 01247 if (*(DWORD *)msg->Buffer) 01248 orpcthis->extensions = orpc_ext_array; 01249 else 01250 orpcthis->extensions = NULL; 01251 01252 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); 01253 01254 if (orpcthis->extensions) 01255 { 01256 HRESULT hr = unmarshal_ORPC_EXTENT_ARRAY(msg, end, orpc_ext_array, 01257 first_wire_orpc_extent); 01258 if (FAILED(hr)) 01259 return hr; 01260 } 01261 01262 if ((orpcthis->version.MajorVersion != COM_MAJOR_VERSION) || 01263 (orpcthis->version.MinorVersion > COM_MINOR_VERSION)) 01264 { 01265 ERR("COM version {%d, %d} not supported\n", 01266 orpcthis->version.MajorVersion, orpcthis->version.MinorVersion); 01267 return RPC_E_VERSION_MISMATCH; 01268 } 01269 01270 if (orpcthis->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4)) 01271 { 01272 ERR("invalid flags 0x%x\n", orpcthis->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4)); 01273 return RPC_E_INVALID_HEADER; 01274 } 01275 01276 return S_OK; 01277 } 01278 01279 static HRESULT unmarshal_ORPCTHAT(RPC_MESSAGE *msg, ORPCTHAT *orpcthat, 01280 ORPC_EXTENT_ARRAY *orpc_ext_array, WIRE_ORPC_EXTENT **first_wire_orpc_extent) 01281 { 01282 const char *end = (char *)msg->Buffer + msg->BufferLength; 01283 01284 *first_wire_orpc_extent = NULL; 01285 01286 if (msg->BufferLength < FIELD_OFFSET(WIRE_ORPCTHAT, extensions) + sizeof(DWORD)) 01287 { 01288 ERR("invalid buffer length\n"); 01289 return RPC_E_INVALID_HEADER; 01290 } 01291 01292 memcpy(orpcthat, msg->Buffer, FIELD_OFFSET(WIRE_ORPCTHAT, extensions)); 01293 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPCTHAT, extensions); 01294 01295 if ((const char *)msg->Buffer + sizeof(DWORD) > end) 01296 return RPC_E_INVALID_HEADER; 01297 01298 if (*(DWORD *)msg->Buffer) 01299 orpcthat->extensions = orpc_ext_array; 01300 else 01301 orpcthat->extensions = NULL; 01302 01303 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD); 01304 01305 if (orpcthat->extensions) 01306 { 01307 HRESULT hr = unmarshal_ORPC_EXTENT_ARRAY(msg, end, orpc_ext_array, 01308 first_wire_orpc_extent); 01309 if (FAILED(hr)) 01310 return hr; 01311 } 01312 01313 if (orpcthat->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4)) 01314 { 01315 ERR("invalid flags 0x%x\n", orpcthat->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4)); 01316 return RPC_E_INVALID_HEADER; 01317 } 01318 01319 return S_OK; 01320 } 01321 01322 void RPC_ExecuteCall(struct dispatch_params *params) 01323 { 01324 struct message_state *message_state = NULL; 01325 RPC_MESSAGE *msg = (RPC_MESSAGE *)params->msg; 01326 char *original_buffer = msg->Buffer; 01327 ORPCTHIS orpcthis; 01328 ORPC_EXTENT_ARRAY orpc_ext_array; 01329 WIRE_ORPC_EXTENT *first_wire_orpc_extent; 01330 GUID old_causality_id; 01331 01332 /* handle ORPCTHIS and server extensions */ 01333 01334 params->hr = unmarshal_ORPCTHIS(msg, &orpcthis, &orpc_ext_array, &first_wire_orpc_extent); 01335 if (params->hr != S_OK) 01336 { 01337 msg->Buffer = original_buffer; 01338 goto exit; 01339 } 01340 01341 message_state = HeapAlloc(GetProcessHeap(), 0, sizeof(*message_state)); 01342 if (!message_state) 01343 { 01344 params->hr = E_OUTOFMEMORY; 01345 msg->Buffer = original_buffer; 01346 goto exit; 01347 } 01348 01349 message_state->prefix_data_len = (char *)msg->Buffer - original_buffer; 01350 message_state->binding_handle = msg->Handle; 01351 message_state->bypass_rpcrt = params->bypass_rpcrt; 01352 01353 message_state->channel_hook_info.iid = params->iid; 01354 message_state->channel_hook_info.cbSize = sizeof(message_state->channel_hook_info); 01355 message_state->channel_hook_info.uCausality = orpcthis.cid; 01356 message_state->channel_hook_info.dwServerPid = GetCurrentProcessId(); 01357 message_state->channel_hook_info.iMethod = msg->ProcNum; 01358 message_state->channel_hook_info.pObject = params->iface; 01359 01360 if (orpcthis.extensions && first_wire_orpc_extent && 01361 orpcthis.extensions->size) 01362 ChannelHooks_ServerNotify(&message_state->channel_hook_info, msg->DataRepresentation, first_wire_orpc_extent, orpcthis.extensions->size); 01363 01364 msg->Handle = message_state; 01365 msg->BufferLength -= message_state->prefix_data_len; 01366 01367 /* call message filter */ 01368 01369 if (COM_CurrentApt()->filter) 01370 { 01371 DWORD handlecall; 01372 INTERFACEINFO interface_info; 01373 CALLTYPE calltype; 01374 01375 interface_info.pUnk = params->iface; 01376 interface_info.iid = params->iid; 01377 interface_info.wMethod = msg->ProcNum; 01378 01379 if (IsEqualGUID(&orpcthis.cid, &COM_CurrentInfo()->causality_id)) 01380 calltype = CALLTYPE_NESTED; 01381 else if (COM_CurrentInfo()->pending_call_count_server == 0) 01382 calltype = CALLTYPE_TOPLEVEL; 01383 else 01384 calltype = CALLTYPE_TOPLEVEL_CALLPENDING; 01385 01386 handlecall = IMessageFilter_HandleInComingCall(COM_CurrentApt()->filter, 01387 calltype, 01388 UlongToHandle(GetCurrentProcessId()), 01389 0 /* FIXME */, 01390 &interface_info); 01391 TRACE("IMessageFilter_HandleInComingCall returned %d\n", handlecall); 01392 switch (handlecall) 01393 { 01394 case SERVERCALL_REJECTED: 01395 params->hr = RPC_E_CALL_REJECTED; 01396 goto exit_reset_state; 01397 case SERVERCALL_RETRYLATER: 01398 #if 0 /* FIXME: handle retries on the client side before enabling this code */ 01399 params->hr = RPC_E_RETRY; 01400 goto exit_reset_state; 01401 #else 01402 FIXME("retry call later not implemented\n"); 01403 break; 01404 #endif 01405 case SERVERCALL_ISHANDLED: 01406 default: 01407 break; 01408 } 01409 } 01410 01411 /* invoke the method */ 01412 01413 /* save the old causality ID - note: any calls executed while processing 01414 * messages received during the SendReceive will appear to originate from 01415 * this call - this should be checked with what Windows does */ 01416 old_causality_id = COM_CurrentInfo()->causality_id; 01417 COM_CurrentInfo()->causality_id = orpcthis.cid; 01418 COM_CurrentInfo()->pending_call_count_server++; 01419 params->hr = IRpcStubBuffer_Invoke(params->stub, params->msg, params->chan); 01420 COM_CurrentInfo()->pending_call_count_server--; 01421 COM_CurrentInfo()->causality_id = old_causality_id; 01422 01423 /* the invoke allocated a new buffer, so free the old one */ 01424 if (message_state->bypass_rpcrt && original_buffer != msg->Buffer) 01425 HeapFree(GetProcessHeap(), 0, original_buffer); 01426 01427 exit_reset_state: 01428 message_state = msg->Handle; 01429 msg->Handle = message_state->binding_handle; 01430 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len; 01431 msg->BufferLength += message_state->prefix_data_len; 01432 01433 exit: 01434 HeapFree(GetProcessHeap(), 0, message_state); 01435 if (params->handle) SetEvent(params->handle); 01436 } 01437 01438 static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg) 01439 { 01440 struct dispatch_params *params; 01441 APARTMENT *apt; 01442 IPID ipid; 01443 HRESULT hr; 01444 01445 RpcBindingInqObject(msg->Handle, &ipid); 01446 01447 TRACE("ipid = %s, iMethod = %d\n", debugstr_guid(&ipid), msg->ProcNum); 01448 01449 params = HeapAlloc(GetProcessHeap(), 0, sizeof(*params)); 01450 if (!params) 01451 { 01452 RpcRaiseException(E_OUTOFMEMORY); 01453 return; 01454 } 01455 01456 hr = ipid_get_dispatch_params(&ipid, &apt, ¶ms->stub, ¶ms->chan, 01457 ¶ms->iid, ¶ms->iface); 01458 if (hr != S_OK) 01459 { 01460 ERR("no apartment found for ipid %s\n", debugstr_guid(&ipid)); 01461 HeapFree(GetProcessHeap(), 0, params); 01462 RpcRaiseException(hr); 01463 return; 01464 } 01465 01466 params->msg = (RPCOLEMESSAGE *)msg; 01467 params->status = RPC_S_OK; 01468 params->hr = S_OK; 01469 params->handle = NULL; 01470 params->bypass_rpcrt = FALSE; 01471 01472 /* Note: this is the important difference between STAs and MTAs - we 01473 * always execute RPCs to STAs in the thread that originally created the 01474 * apartment (i.e. the one that pumps messages to the window) */ 01475 if (!apt->multi_threaded) 01476 { 01477 params->handle = CreateEventW(NULL, FALSE, FALSE, NULL); 01478 01479 TRACE("Calling apartment thread 0x%08x...\n", apt->tid); 01480 01481 if (PostMessageW(apartment_getwindow(apt), DM_EXECUTERPC, 0, (LPARAM)params)) 01482 WaitForSingleObject(params->handle, INFINITE); 01483 else 01484 { 01485 ERR("PostMessage failed with error %u\n", GetLastError()); 01486 IRpcChannelBuffer_Release(params->chan); 01487 IRpcStubBuffer_Release(params->stub); 01488 } 01489 CloseHandle(params->handle); 01490 } 01491 else 01492 { 01493 BOOL joined = FALSE; 01494 if (!COM_CurrentInfo()->apt) 01495 { 01496 apartment_joinmta(); 01497 joined = TRUE; 01498 } 01499 RPC_ExecuteCall(params); 01500 if (joined) 01501 { 01502 apartment_release(COM_CurrentInfo()->apt); 01503 COM_CurrentInfo()->apt = NULL; 01504 } 01505 } 01506 01507 hr = params->hr; 01508 if (params->chan) 01509 IRpcChannelBuffer_Release(params->chan); 01510 if (params->stub) 01511 IRpcStubBuffer_Release(params->stub); 01512 HeapFree(GetProcessHeap(), 0, params); 01513 01514 apartment_release(apt); 01515 01516 /* if IRpcStubBuffer_Invoke fails, we should raise an exception to tell 01517 * the RPC runtime that the call failed */ 01518 if (hr) RpcRaiseException(hr); 01519 } 01520 01521 /* stub registration */ 01522 HRESULT RPC_RegisterInterface(REFIID riid) 01523 { 01524 struct registered_if *rif; 01525 BOOL found = FALSE; 01526 HRESULT hr = S_OK; 01527 01528 TRACE("(%s)\n", debugstr_guid(riid)); 01529 01530 EnterCriticalSection(&csRegIf); 01531 LIST_FOR_EACH_ENTRY(rif, ®istered_interfaces, struct registered_if, entry) 01532 { 01533 if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid)) 01534 { 01535 rif->refs++; 01536 found = TRUE; 01537 break; 01538 } 01539 } 01540 if (!found) 01541 { 01542 TRACE("Creating new interface\n"); 01543 01544 rif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rif)); 01545 if (rif) 01546 { 01547 RPC_STATUS status; 01548 01549 rif->refs = 1; 01550 rif->If.Length = sizeof(RPC_SERVER_INTERFACE); 01551 /* RPC interface ID = COM interface ID */ 01552 rif->If.InterfaceId.SyntaxGUID = *riid; 01553 rif->If.DispatchTable = &rpc_dispatch; 01554 /* all other fields are 0, including the version asCOM objects 01555 * always have a version of 0.0 */ 01556 status = RpcServerRegisterIfEx( 01557 (RPC_IF_HANDLE)&rif->If, 01558 NULL, NULL, 01559 RPC_IF_OLE | RPC_IF_AUTOLISTEN, 01560 RPC_C_LISTEN_MAX_CALLS_DEFAULT, 01561 NULL); 01562 if (status == RPC_S_OK) 01563 list_add_tail(®istered_interfaces, &rif->entry); 01564 else 01565 { 01566 ERR("RpcServerRegisterIfEx failed with error %d\n", status); 01567 HeapFree(GetProcessHeap(), 0, rif); 01568 hr = HRESULT_FROM_WIN32(status); 01569 } 01570 } 01571 else 01572 hr = E_OUTOFMEMORY; 01573 } 01574 LeaveCriticalSection(&csRegIf); 01575 return hr; 01576 } 01577 01578 /* stub unregistration */ 01579 void RPC_UnregisterInterface(REFIID riid) 01580 { 01581 struct registered_if *rif; 01582 EnterCriticalSection(&csRegIf); 01583 LIST_FOR_EACH_ENTRY(rif, ®istered_interfaces, struct registered_if, entry) 01584 { 01585 if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid)) 01586 { 01587 if (!--rif->refs) 01588 { 01589 RpcServerUnregisterIf((RPC_IF_HANDLE)&rif->If, NULL, TRUE); 01590 list_remove(&rif->entry); 01591 HeapFree(GetProcessHeap(), 0, rif); 01592 } 01593 break; 01594 } 01595 } 01596 LeaveCriticalSection(&csRegIf); 01597 } 01598 01599 /* get the info for an OXID, including the IPID for the rem unknown interface 01600 * and the string binding */ 01601 HRESULT RPC_ResolveOxid(OXID oxid, OXID_INFO *oxid_info) 01602 { 01603 TRACE("%s\n", wine_dbgstr_longlong(oxid)); 01604 01605 oxid_info->dwTid = 0; 01606 oxid_info->dwPid = 0; 01607 oxid_info->dwAuthnHint = RPC_C_AUTHN_LEVEL_NONE; 01608 /* FIXME: this is a hack around not having an OXID resolver yet - 01609 * this function should contact the machine's OXID resolver and then it 01610 * should give us the IPID of the IRemUnknown interface */ 01611 oxid_info->ipidRemUnknown.Data1 = 0xffffffff; 01612 oxid_info->ipidRemUnknown.Data2 = 0xffff; 01613 oxid_info->ipidRemUnknown.Data3 = 0xffff; 01614 memcpy(oxid_info->ipidRemUnknown.Data4, &oxid, sizeof(OXID)); 01615 oxid_info->psa = NULL /* FIXME */; 01616 01617 return S_OK; 01618 } 01619 01620 /* make the apartment reachable by other threads and processes and create the 01621 * IRemUnknown object */ 01622 void RPC_StartRemoting(struct apartment *apt) 01623 { 01624 if (!InterlockedExchange(&apt->remoting_started, TRUE)) 01625 { 01626 WCHAR endpoint[200]; 01627 RPC_STATUS status; 01628 01629 get_rpc_endpoint(endpoint, &apt->oxid); 01630 01631 status = RpcServerUseProtseqEpW( 01632 wszRpcTransport, 01633 RPC_C_PROTSEQ_MAX_REQS_DEFAULT, 01634 endpoint, 01635 NULL); 01636 if (status != RPC_S_OK) 01637 ERR("Couldn't register endpoint %s\n", debugstr_w(endpoint)); 01638 01639 /* FIXME: move remote unknown exporting into this function */ 01640 } 01641 start_apartment_remote_unknown(); 01642 } 01643 01644 01645 static HRESULT create_server(REFCLSID rclsid, HANDLE *process) 01646 { 01647 static const WCHAR wszLocalServer32[] = { 'L','o','c','a','l','S','e','r','v','e','r','3','2',0 }; 01648 static const WCHAR embedding[] = { ' ', '-','E','m','b','e','d','d','i','n','g',0 }; 01649 HKEY key; 01650 HRESULT hres; 01651 WCHAR command[MAX_PATH+sizeof(embedding)/sizeof(WCHAR)]; 01652 DWORD size = (MAX_PATH+1) * sizeof(WCHAR); 01653 STARTUPINFOW sinfo; 01654 PROCESS_INFORMATION pinfo; 01655 01656 hres = COM_OpenKeyForCLSID(rclsid, wszLocalServer32, KEY_READ, &key); 01657 if (FAILED(hres)) { 01658 ERR("class %s not registered\n", debugstr_guid(rclsid)); 01659 return hres; 01660 } 01661 01662 hres = RegQueryValueExW(key, NULL, NULL, NULL, (LPBYTE)command, &size); 01663 RegCloseKey(key); 01664 if (hres) { 01665 WARN("No default value for LocalServer32 key\n"); 01666 return REGDB_E_CLASSNOTREG; /* FIXME: check retval */ 01667 } 01668 01669 memset(&sinfo,0,sizeof(sinfo)); 01670 sinfo.cb = sizeof(sinfo); 01671 01672 /* EXE servers are started with the -Embedding switch. */ 01673 01674 strcatW(command, embedding); 01675 01676 TRACE("activating local server %s for %s\n", debugstr_w(command), debugstr_guid(rclsid)); 01677 01678 /* FIXME: Win2003 supports a ServerExecutable value that is passed into 01679 * CreateProcess */ 01680 if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo)) { 01681 WARN("failed to run local server %s\n", debugstr_w(command)); 01682 return HRESULT_FROM_WIN32(GetLastError()); 01683 } 01684 *process = pinfo.hProcess; 01685 CloseHandle(pinfo.hThread); 01686 01687 return S_OK; 01688 } 01689 01690 /* 01691 * start_local_service() - start a service given its name and parameters 01692 */ 01693 static DWORD start_local_service(LPCWSTR name, DWORD num, LPCWSTR *params) 01694 { 01695 SC_HANDLE handle, hsvc; 01696 DWORD r = ERROR_FUNCTION_FAILED; 01697 01698 TRACE("Starting service %s %d params\n", debugstr_w(name), num); 01699 01700 handle = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); 01701 if (!handle) 01702 return r; 01703 hsvc = OpenServiceW(handle, name, SERVICE_START); 01704 if (hsvc) 01705 { 01706 if(StartServiceW(hsvc, num, params)) 01707 r = ERROR_SUCCESS; 01708 else 01709 r = GetLastError(); 01710 if (r == ERROR_SERVICE_ALREADY_RUNNING) 01711 r = ERROR_SUCCESS; 01712 CloseServiceHandle(hsvc); 01713 } 01714 else 01715 r = GetLastError(); 01716 CloseServiceHandle(handle); 01717 01718 TRACE("StartService returned error %u (%s)\n", r, (r == ERROR_SUCCESS) ? "ok":"failed"); 01719 01720 return r; 01721 } 01722 01723 /* 01724 * create_local_service() - start a COM server in a service 01725 * 01726 * To start a Local Service, we read the AppID value under 01727 * the class's CLSID key, then open the HKCR\\AppId key specified 01728 * there and check for a LocalService value. 01729 * 01730 * Note: Local Services are not supported under Windows 9x 01731 */ 01732 static HRESULT create_local_service(REFCLSID rclsid) 01733 { 01734 HRESULT hres; 01735 WCHAR buf[CHARS_IN_GUID]; 01736 static const WCHAR szLocalService[] = { 'L','o','c','a','l','S','e','r','v','i','c','e',0 }; 01737 static const WCHAR szServiceParams[] = {'S','e','r','v','i','c','e','P','a','r','a','m','s',0}; 01738 HKEY hkey; 01739 LONG r; 01740 DWORD type, sz; 01741 01742 TRACE("Attempting to start Local service for %s\n", debugstr_guid(rclsid)); 01743 01744 hres = COM_OpenKeyForAppIdFromCLSID(rclsid, KEY_READ, &hkey); 01745 if (FAILED(hres)) 01746 return hres; 01747 01748 /* read the LocalService and ServiceParameters values from the AppID key */ 01749 sz = sizeof buf; 01750 r = RegQueryValueExW(hkey, szLocalService, NULL, &type, (LPBYTE)buf, &sz); 01751 if (r==ERROR_SUCCESS && type==REG_SZ) 01752 { 01753 DWORD num_args = 0; 01754 LPWSTR args[1] = { NULL }; 01755 01756 /* 01757 * FIXME: I'm not really sure how to deal with the service parameters. 01758 * I suspect that the string returned from RegQueryValueExW 01759 * should be split into a number of arguments by spaces. 01760 * It would make more sense if ServiceParams contained a 01761 * REG_MULTI_SZ here, but it's a REG_SZ for the services 01762 * that I'm interested in for the moment. 01763 */ 01764 r = RegQueryValueExW(hkey, szServiceParams, NULL, &type, NULL, &sz); 01765 if (r == ERROR_SUCCESS && type == REG_SZ && sz) 01766 { 01767 args[0] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz); 01768 num_args++; 01769 RegQueryValueExW(hkey, szServiceParams, NULL, &type, (LPBYTE)args[0], &sz); 01770 } 01771 r = start_local_service(buf, num_args, (LPCWSTR *)args); 01772 if (r != ERROR_SUCCESS) 01773 hres = REGDB_E_CLASSNOTREG; /* FIXME: check retval */ 01774 HeapFree(GetProcessHeap(),0,args[0]); 01775 } 01776 else 01777 { 01778 WARN("No LocalService value\n"); 01779 hres = REGDB_E_CLASSNOTREG; /* FIXME: check retval */ 01780 } 01781 RegCloseKey(hkey); 01782 01783 return hres; 01784 } 01785 01786 01787 static void get_localserver_pipe_name(WCHAR *pipefn, REFCLSID rclsid) 01788 { 01789 static const WCHAR wszPipeRef[] = {'\\','\\','.','\\','p','i','p','e','\\',0}; 01790 strcpyW(pipefn, wszPipeRef); 01791 StringFromGUID2(rclsid, pipefn + sizeof(wszPipeRef)/sizeof(wszPipeRef[0]) - 1, CHARS_IN_GUID); 01792 } 01793 01794 /* FIXME: should call to rpcss instead */ 01795 HRESULT RPC_GetLocalClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv) 01796 { 01797 HRESULT hres; 01798 HANDLE hPipe; 01799 WCHAR pipefn[100]; 01800 DWORD res, bufferlen; 01801 char marshalbuffer[200]; 01802 IStream *pStm; 01803 LARGE_INTEGER seekto; 01804 ULARGE_INTEGER newpos; 01805 int tries = 0; 01806 01807 static const int MAXTRIES = 30; /* 30 seconds */ 01808 01809 TRACE("rclsid=%s, iid=%s\n", debugstr_guid(rclsid), debugstr_guid(iid)); 01810 01811 get_localserver_pipe_name(pipefn, rclsid); 01812 01813 while (tries++ < MAXTRIES) { 01814 TRACE("waiting for %s\n", debugstr_w(pipefn)); 01815 01816 WaitNamedPipeW( pipefn, NMPWAIT_WAIT_FOREVER ); 01817 hPipe = CreateFileW(pipefn, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); 01818 if (hPipe == INVALID_HANDLE_VALUE) { 01819 DWORD index; 01820 DWORD start_ticks; 01821 HANDLE process = 0; 01822 if (tries == 1) { 01823 if ( (hres = create_local_service(rclsid)) && 01824 (hres = create_server(rclsid, &process)) ) 01825 return hres; 01826 } else { 01827 WARN("Connecting to %s, no response yet, retrying: le is %u\n", debugstr_w(pipefn), GetLastError()); 01828 } 01829 /* wait for one second, even if messages arrive */ 01830 start_ticks = GetTickCount(); 01831 do { 01832 if (SUCCEEDED(CoWaitForMultipleHandles(0, 1000, (process != 0), 01833 &process, &index)) && process && !index) 01834 { 01835 WARN( "server for %s failed to start\n", debugstr_guid(rclsid) ); 01836 CloseHandle( hPipe ); 01837 CloseHandle( process ); 01838 return E_NOINTERFACE; 01839 } 01840 } while (GetTickCount() - start_ticks < 1000); 01841 if (process) CloseHandle( process ); 01842 continue; 01843 } 01844 bufferlen = 0; 01845 if (!ReadFile(hPipe,marshalbuffer,sizeof(marshalbuffer),&bufferlen,NULL)) { 01846 FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid)); 01847 Sleep(1000); 01848 continue; 01849 } 01850 TRACE("read marshal id from pipe\n"); 01851 CloseHandle(hPipe); 01852 break; 01853 } 01854 01855 if (tries >= MAXTRIES) 01856 return E_NOINTERFACE; 01857 01858 hres = CreateStreamOnHGlobal(0,TRUE,&pStm); 01859 if (hres) return hres; 01860 hres = IStream_Write(pStm,marshalbuffer,bufferlen,&res); 01861 if (hres) goto out; 01862 seekto.u.LowPart = 0;seekto.u.HighPart = 0; 01863 hres = IStream_Seek(pStm,seekto,STREAM_SEEK_SET,&newpos); 01864 01865 TRACE("unmarshalling classfactory\n"); 01866 hres = CoUnmarshalInterface(pStm,&IID_IClassFactory,ppv); 01867 out: 01868 IStream_Release(pStm); 01869 return hres; 01870 } 01871 01872 01873 struct local_server_params 01874 { 01875 CLSID clsid; 01876 IStream *stream; 01877 HANDLE ready_event; 01878 HANDLE stop_event; 01879 HANDLE thread; 01880 BOOL multi_use; 01881 }; 01882 01883 /* FIXME: should call to rpcss instead */ 01884 static DWORD WINAPI local_server_thread(LPVOID param) 01885 { 01886 struct local_server_params * lsp = param; 01887 WCHAR pipefn[100]; 01888 HRESULT hres; 01889 IStream *pStm = lsp->stream; 01890 STATSTG ststg; 01891 unsigned char *buffer; 01892 int buflen; 01893 LARGE_INTEGER seekto; 01894 ULARGE_INTEGER newpos; 01895 ULONG res; 01896 BOOL multi_use = lsp->multi_use; 01897 OVERLAPPED ovl; 01898 HANDLE pipe_event, hPipe, new_pipe; 01899 DWORD bytes; 01900 01901 TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid)); 01902 01903 memset(&ovl, 0, sizeof(ovl)); 01904 get_localserver_pipe_name(pipefn, &lsp->clsid); 01905 ovl.hEvent = pipe_event = CreateEventW(NULL, FALSE, FALSE, NULL); 01906 01907 hPipe = CreateNamedPipeW( pipefn, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 01908 PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 01909 4096, 4096, 500 /* 0.5 second timeout */, NULL ); 01910 if (hPipe == INVALID_HANDLE_VALUE) 01911 { 01912 FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError()); 01913 CloseHandle(pipe_event); 01914 return 1; 01915 } 01916 01917 SetEvent(lsp->ready_event); 01918 01919 while (1) { 01920 if (!ConnectNamedPipe(hPipe, &ovl)) 01921 { 01922 DWORD error = GetLastError(); 01923 if (error == ERROR_IO_PENDING) 01924 { 01925 HANDLE handles[2] = { pipe_event, lsp->stop_event }; 01926 DWORD ret; 01927 ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE); 01928 if (ret != WAIT_OBJECT_0) 01929 { 01930 CloseHandle(hPipe); 01931 break; 01932 } 01933 } 01934 /* client already connected isn't an error */ 01935 else if (error != ERROR_PIPE_CONNECTED) 01936 { 01937 ERR("ConnectNamedPipe failed with error %d\n", GetLastError()); 01938 CloseHandle(hPipe); 01939 break; 01940 } 01941 } 01942 01943 TRACE("marshalling IClassFactory to client\n"); 01944 01945 hres = IStream_Stat(pStm,&ststg,STATFLAG_NONAME); 01946 if (hres) 01947 { 01948 CloseHandle(hPipe); 01949 CloseHandle(pipe_event); 01950 return hres; 01951 } 01952 01953 seekto.u.LowPart = 0; 01954 seekto.u.HighPart = 0; 01955 hres = IStream_Seek(pStm,seekto,STREAM_SEEK_SET,&newpos); 01956 if (hres) { 01957 FIXME("IStream_Seek failed, %x\n",hres); 01958 CloseHandle(hPipe); 01959 CloseHandle(pipe_event); 01960 return hres; 01961 } 01962 01963 buflen = ststg.cbSize.u.LowPart; 01964 buffer = HeapAlloc(GetProcessHeap(),0,buflen); 01965 01966 hres = IStream_Read(pStm,buffer,buflen,&res); 01967 if (hres) { 01968 FIXME("Stream Read failed, %x\n",hres); 01969 CloseHandle(hPipe); 01970 CloseHandle(pipe_event); 01971 HeapFree(GetProcessHeap(),0,buffer); 01972 return hres; 01973 } 01974 01975 WriteFile(hPipe,buffer,buflen,&res,&ovl); 01976 GetOverlappedResult(hPipe, &ovl, &bytes, TRUE); 01977 HeapFree(GetProcessHeap(),0,buffer); 01978 01979 FlushFileBuffers(hPipe); 01980 DisconnectNamedPipe(hPipe); 01981 TRACE("done marshalling IClassFactory\n"); 01982 01983 if (!multi_use) 01984 { 01985 TRACE("single use object, shutting down pipe %s\n", debugstr_w(pipefn)); 01986 CloseHandle(hPipe); 01987 break; 01988 } 01989 new_pipe = CreateNamedPipeW( pipefn, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 01990 PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 01991 4096, 4096, 500 /* 0.5 second timeout */, NULL ); 01992 CloseHandle(hPipe); 01993 if (new_pipe == INVALID_HANDLE_VALUE) 01994 { 01995 FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError()); 01996 CloseHandle(pipe_event); 01997 return 1; 01998 } 01999 hPipe = new_pipe; 02000 } 02001 CloseHandle(pipe_event); 02002 return 0; 02003 } 02004 02005 /* starts listening for a local server */ 02006 HRESULT RPC_StartLocalServer(REFCLSID clsid, IStream *stream, BOOL multi_use, void **registration) 02007 { 02008 DWORD tid; 02009 struct local_server_params *lsp; 02010 02011 lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp)); 02012 if (!lsp) 02013 return E_OUTOFMEMORY; 02014 02015 lsp->clsid = *clsid; 02016 lsp->stream = stream; 02017 IStream_AddRef(stream); 02018 lsp->ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); 02019 if (!lsp->ready_event) 02020 { 02021 HeapFree(GetProcessHeap(), 0, lsp); 02022 return HRESULT_FROM_WIN32(GetLastError()); 02023 } 02024 lsp->stop_event = CreateEventW(NULL, FALSE, FALSE, NULL); 02025 if (!lsp->stop_event) 02026 { 02027 CloseHandle(lsp->ready_event); 02028 HeapFree(GetProcessHeap(), 0, lsp); 02029 return HRESULT_FROM_WIN32(GetLastError()); 02030 } 02031 lsp->multi_use = multi_use; 02032 02033 lsp->thread = CreateThread(NULL, 0, local_server_thread, lsp, 0, &tid); 02034 if (!lsp->thread) 02035 { 02036 CloseHandle(lsp->ready_event); 02037 CloseHandle(lsp->stop_event); 02038 HeapFree(GetProcessHeap(), 0, lsp); 02039 return HRESULT_FROM_WIN32(GetLastError()); 02040 } 02041 02042 WaitForSingleObject(lsp->ready_event, INFINITE); 02043 CloseHandle(lsp->ready_event); 02044 lsp->ready_event = NULL; 02045 02046 *registration = lsp; 02047 return S_OK; 02048 } 02049 02050 /* stops listening for a local server */ 02051 void RPC_StopLocalServer(void *registration) 02052 { 02053 struct local_server_params *lsp = registration; 02054 02055 /* signal local_server_thread to stop */ 02056 SetEvent(lsp->stop_event); 02057 /* wait for it to exit */ 02058 WaitForSingleObject(lsp->thread, INFINITE); 02059 02060 IStream_Release(lsp->stream); 02061 CloseHandle(lsp->stop_event); 02062 CloseHandle(lsp->thread); 02063 HeapFree(GetProcessHeap(), 0, lsp); 02064 } Generated on Sat May 26 2012 04:16:37 for ReactOS by
1.7.6.1
|