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