win32u: Move NtUserTranslateMessage implementation from user32.
[wine.git] / dlls / combase / rpc.c
blob80760ca37e7650e87bdae5d4b09e049bc66f4d42
1 /*
2 * Copyright 2001 Ove Kåven, TransGaming Technologies
3 * Copyright 2002 Marcus Meissner
4 * Copyright 2005 Mike Hearn, Rob Shearman for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winsvc.h"
28 #include "servprov.h"
30 #include "wine/debug.h"
31 #include "wine/exception.h"
32 #include "wine/heap.h"
34 #include "combase_private.h"
36 #include "irpcss.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(ole);
40 static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg);
42 /* we only use one function to dispatch calls for all methods - we use the
43 * RPC_IF_OLE flag to tell the RPC runtime that this is the case */
44 static RPC_DISPATCH_FUNCTION rpc_dispatch_table[1] = { dispatch_rpc }; /* (RO) */
45 static RPC_DISPATCH_TABLE rpc_dispatch = { 1, rpc_dispatch_table }; /* (RO) */
47 static struct list registered_interfaces = LIST_INIT(registered_interfaces); /* (CS csRegIf) */
48 static CRITICAL_SECTION csRegIf;
49 static CRITICAL_SECTION_DEBUG csRegIf_debug =
51 0, 0, &csRegIf,
52 { &csRegIf_debug.ProcessLocksList, &csRegIf_debug.ProcessLocksList },
53 0, 0, { (DWORD_PTR)(__FILE__ ": dcom registered server interfaces") }
55 static CRITICAL_SECTION csRegIf = { &csRegIf_debug, -1, 0, 0, 0, 0 };
57 static struct list channel_hooks = LIST_INIT(channel_hooks); /* (CS csChannelHook) */
58 static CRITICAL_SECTION csChannelHook;
59 static CRITICAL_SECTION_DEBUG csChannelHook_debug =
61 0, 0, &csChannelHook,
62 { &csChannelHook_debug.ProcessLocksList, &csChannelHook_debug.ProcessLocksList },
63 0, 0, { (DWORD_PTR)(__FILE__ ": channel hooks") }
65 static CRITICAL_SECTION csChannelHook = { &csChannelHook_debug, -1, 0, 0, 0, 0 };
67 static WCHAR rpctransportW[] = L"ncalrpc";
69 struct registered_if
71 struct list entry;
72 DWORD refs; /* ref count */
73 RPC_SERVER_INTERFACE If; /* interface registered with the RPC runtime */
76 /* get the pipe endpoint specified of the specified apartment */
77 static inline void get_rpc_endpoint(LPWSTR endpoint, const OXID *oxid)
79 /* FIXME: should get endpoint from rpcss */
80 wsprintfW(endpoint, L"\\pipe\\OLE_%016I64x", *oxid);
83 typedef struct
85 IRpcChannelBuffer IRpcChannelBuffer_iface;
86 LONG refs;
88 DWORD dest_context; /* returned from GetDestCtx */
89 void *dest_context_data; /* returned from GetDestCtx */
90 } RpcChannelBuffer;
92 typedef struct
94 RpcChannelBuffer super; /* superclass */
96 RPC_BINDING_HANDLE bind; /* handle to the remote server */
97 OXID oxid; /* apartment in which the channel is valid */
98 DWORD server_pid; /* id of server process */
99 HANDLE event; /* cached event handle */
100 IID iid; /* IID of the proxy this belongs to */
101 } ClientRpcChannelBuffer;
103 struct dispatch_params
105 RPCOLEMESSAGE *msg; /* message */
106 IRpcStubBuffer *stub; /* stub buffer, if applicable */
107 IRpcChannelBuffer *chan; /* server channel buffer, if applicable */
108 IID iid; /* ID of interface being called */
109 IUnknown *iface; /* interface being called */
110 HANDLE handle; /* handle that will become signaled when call finishes */
111 BOOL bypass_rpcrt; /* bypass RPC runtime? */
112 RPC_STATUS status; /* status (out) */
113 HRESULT hr; /* hresult (out) */
116 struct message_state
118 RPC_BINDING_HANDLE binding_handle;
119 ULONG prefix_data_len;
120 SChannelHookCallInfo channel_hook_info;
121 BOOL bypass_rpcrt;
123 /* client only */
124 HWND target_hwnd;
125 DWORD target_tid;
126 struct dispatch_params params;
129 typedef struct
131 ULONG conformance; /* NDR */
132 GUID id;
133 ULONG size;
134 /* [size_is((size+7)&~7)] */ unsigned char data[1];
135 } WIRE_ORPC_EXTENT;
137 typedef struct
139 ULONG size;
140 ULONG reserved;
141 unsigned char extent[1];
142 } WIRE_ORPC_EXTENT_ARRAY;
144 typedef struct
146 ULONG version;
147 ULONG flags;
148 ULONG reserved1;
149 GUID cid;
150 unsigned char extensions[1];
151 } WIRE_ORPCTHIS;
153 typedef struct
155 ULONG flags;
156 unsigned char extensions[1];
157 } WIRE_ORPCTHAT;
159 struct channel_hook_entry
161 struct list entry;
162 GUID id;
163 IChannelHook *hook;
166 struct channel_hook_buffer_data
168 GUID id;
169 ULONG extension_size;
171 void * __RPC_USER MIDL_user_allocate(SIZE_T size)
173 return heap_alloc(size);
176 void __RPC_USER MIDL_user_free(void *p)
178 heap_free(p);
181 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr)
183 return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode);
186 static BOOL start_rpcss(void)
188 SERVICE_STATUS_PROCESS status;
189 SC_HANDLE scm, service;
190 BOOL ret = FALSE;
192 TRACE("\n");
194 if (!(scm = OpenSCManagerW(NULL, NULL, 0)))
196 ERR("Failed to open service manager\n");
197 return FALSE;
200 if (!(service = OpenServiceW(scm, L"RpcSs", SERVICE_START | SERVICE_QUERY_STATUS)))
202 ERR("Failed to open RpcSs service\n");
203 CloseServiceHandle( scm );
204 return FALSE;
207 if (StartServiceW(service, 0, NULL) || GetLastError() == ERROR_SERVICE_ALREADY_RUNNING)
209 ULONGLONG start_time = GetTickCount64();
212 DWORD dummy;
214 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (BYTE *)&status, sizeof(status), &dummy))
215 break;
216 if (status.dwCurrentState == SERVICE_RUNNING)
218 ret = TRUE;
219 break;
221 if (GetTickCount64() - start_time > 30000) break;
222 Sleep( 100 );
224 } while (status.dwCurrentState == SERVICE_START_PENDING);
226 if (status.dwCurrentState != SERVICE_RUNNING)
227 WARN("RpcSs failed to start %lu\n", status.dwCurrentState);
229 else
230 ERR("Failed to start RpcSs service\n");
232 CloseServiceHandle(service);
233 CloseServiceHandle(scm);
234 return ret;
237 static RPC_BINDING_HANDLE get_rpc_handle(unsigned short *protseq, unsigned short *endpoint)
239 RPC_BINDING_HANDLE handle = NULL;
240 RPC_STATUS status;
241 RPC_WSTR binding;
243 status = RpcStringBindingComposeW(NULL, protseq, NULL, endpoint, NULL, &binding);
244 if (status == RPC_S_OK)
246 status = RpcBindingFromStringBindingW(binding, &handle);
247 RpcStringFreeW(&binding);
250 return handle;
253 static RPC_BINDING_HANDLE get_irpcss_handle(void)
255 static RPC_BINDING_HANDLE irpcss_handle;
257 if (!irpcss_handle)
259 unsigned short protseq[] = IRPCSS_PROTSEQ;
260 unsigned short endpoint[] = IRPCSS_ENDPOINT;
262 RPC_BINDING_HANDLE new_handle = get_rpc_handle(protseq, endpoint);
263 if (InterlockedCompareExchangePointer(&irpcss_handle, new_handle, NULL))
264 /* another thread beat us to it */
265 RpcBindingFree(&new_handle);
267 return irpcss_handle;
270 static RPC_BINDING_HANDLE get_irot_handle(void)
272 static RPC_BINDING_HANDLE irot_handle;
274 if (!irot_handle)
276 unsigned short protseq[] = IROT_PROTSEQ;
277 unsigned short endpoint[] = IROT_ENDPOINT;
279 RPC_BINDING_HANDLE new_handle = get_rpc_handle(protseq, endpoint);
280 if (InterlockedCompareExchangePointer(&irot_handle, new_handle, NULL))
281 /* another thread beat us to it */
282 RpcBindingFree(&new_handle);
284 return irot_handle;
287 #define RPCSS_CALL_START \
288 HRESULT hr; \
289 for (;;) { \
290 __TRY {
292 #define RPCSS_CALL_END \
293 } __EXCEPT(rpc_filter) { \
294 hr = HRESULT_FROM_WIN32(GetExceptionCode()); \
296 __ENDTRY \
297 if (hr == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE)) { \
298 if (start_rpcss()) \
299 continue; \
301 break; \
303 return hr;
305 HRESULT rpcss_get_next_seqid(DWORD *id)
307 RPCSS_CALL_START
308 hr = irpcss_get_thread_seq_id(get_irpcss_handle(), id);
309 RPCSS_CALL_END
312 HRESULT WINAPI InternalIrotRegister(const MonikerComparisonData *moniker_data,
313 const InterfaceData *object, const InterfaceData *moniker,
314 const FILETIME *time, DWORD flags, IrotCookie *cookie, IrotContextHandle *ctxt_handle)
316 RPCSS_CALL_START
317 hr = IrotRegister(get_irot_handle(), moniker_data, object, moniker, time, flags, cookie, ctxt_handle);
318 RPCSS_CALL_END
321 HRESULT WINAPI InternalIrotIsRunning(const MonikerComparisonData *moniker_data)
323 RPCSS_CALL_START
324 hr = IrotIsRunning(get_irot_handle(), moniker_data);
325 RPCSS_CALL_END
328 HRESULT WINAPI InternalIrotGetObject(const MonikerComparisonData *moniker_data, PInterfaceData *obj,
329 IrotCookie *cookie)
331 RPCSS_CALL_START
332 hr = IrotGetObject(get_irot_handle(), moniker_data, obj, cookie);
333 RPCSS_CALL_END
336 HRESULT WINAPI InternalIrotNoteChangeTime(IrotCookie cookie, const FILETIME *time)
338 RPCSS_CALL_START
339 hr = IrotNoteChangeTime(get_irot_handle(), cookie, time);
340 RPCSS_CALL_END
343 HRESULT WINAPI InternalIrotGetTimeOfLastChange(const MonikerComparisonData *moniker_data, FILETIME *time)
345 RPCSS_CALL_START
346 hr = IrotGetTimeOfLastChange(get_irot_handle(), moniker_data, time);
347 RPCSS_CALL_END
350 HRESULT WINAPI InternalIrotEnumRunning(PInterfaceList *list)
352 RPCSS_CALL_START
353 hr = IrotEnumRunning(get_irot_handle(), list);
354 RPCSS_CALL_END
357 HRESULT WINAPI InternalIrotRevoke(IrotCookie cookie, IrotContextHandle *ctxt_handle, PInterfaceData *object,
358 PInterfaceData *moniker)
360 RPCSS_CALL_START
361 hr = IrotRevoke(get_irot_handle(), cookie, ctxt_handle, object, moniker);
362 RPCSS_CALL_END
365 static HRESULT rpcss_server_register(REFCLSID clsid, DWORD flags, MInterfacePointer *obj, unsigned int *cookie)
367 RPCSS_CALL_START
368 hr = irpcss_server_register(get_irpcss_handle(), clsid, flags, obj, cookie);
369 RPCSS_CALL_END
372 HRESULT rpc_revoke_local_server(unsigned int cookie)
374 RPCSS_CALL_START
375 hr = irpcss_server_revoke(get_irpcss_handle(), cookie);
376 RPCSS_CALL_END
379 static HRESULT rpcss_get_class_object(REFCLSID rclsid, PMInterfacePointer *objref)
381 RPCSS_CALL_START
382 hr = irpcss_get_class_object(get_irpcss_handle(), rclsid, objref);
383 RPCSS_CALL_END
386 static DWORD start_local_service(const WCHAR *name, DWORD num, LPCWSTR *params)
388 SC_HANDLE handle, hsvc;
389 DWORD r = ERROR_FUNCTION_FAILED;
391 TRACE("Starting service %s %ld params\n", debugstr_w(name), num);
393 handle = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
394 if (!handle)
395 return r;
396 hsvc = OpenServiceW(handle, name, SERVICE_START);
397 if (hsvc)
399 if(StartServiceW(hsvc, num, params))
400 r = ERROR_SUCCESS;
401 else
402 r = GetLastError();
403 if (r == ERROR_SERVICE_ALREADY_RUNNING)
404 r = ERROR_SUCCESS;
405 CloseServiceHandle(hsvc);
407 else
408 r = GetLastError();
409 CloseServiceHandle(handle);
411 TRACE("StartService returned error %lu (%s)\n", r, (r == ERROR_SUCCESS) ? "ok":"failed");
413 return r;
417 * create_local_service() - start a COM server in a service
419 * To start a Local Service, we read the AppID value under
420 * the class's CLSID key, then open the HKCR\\AppId key specified
421 * there and check for a LocalService value.
423 * Note: Local Services are not supported under Windows 9x
425 static HRESULT create_local_service(REFCLSID rclsid)
427 HRESULT hr;
428 WCHAR buf[CHARS_IN_GUID];
429 HKEY hkey;
430 LONG r;
431 DWORD type, sz;
433 TRACE("Attempting to start Local service for %s\n", debugstr_guid(rclsid));
435 hr = open_appidkey_from_clsid(rclsid, KEY_READ, &hkey);
436 if (FAILED(hr))
437 return hr;
439 /* read the LocalService and ServiceParameters values from the AppID key */
440 sz = sizeof buf;
441 r = RegQueryValueExW(hkey, L"LocalService", NULL, &type, (LPBYTE)buf, &sz);
442 if (r == ERROR_SUCCESS && type == REG_SZ)
444 DWORD num_args = 0;
445 LPWSTR args[1] = { NULL };
448 * FIXME: I'm not really sure how to deal with the service parameters.
449 * I suspect that the string returned from RegQueryValueExW
450 * should be split into a number of arguments by spaces.
451 * It would make more sense if ServiceParams contained a
452 * REG_MULTI_SZ here, but it's a REG_SZ for the services
453 * that I'm interested in for the moment.
455 r = RegQueryValueExW(hkey, L"ServiceParams", NULL, &type, NULL, &sz);
456 if (r == ERROR_SUCCESS && type == REG_SZ && sz)
458 args[0] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz);
459 num_args++;
460 RegQueryValueExW(hkey, L"ServiceParams", NULL, &type, (LPBYTE)args[0], &sz);
462 r = start_local_service(buf, num_args, (LPCWSTR *)args);
463 if (r != ERROR_SUCCESS)
464 hr = REGDB_E_CLASSNOTREG; /* FIXME: check retval */
465 HeapFree(GetProcessHeap(),0,args[0]);
467 else
469 WARN("No LocalService value\n");
470 hr = REGDB_E_CLASSNOTREG; /* FIXME: check retval */
472 RegCloseKey(hkey);
474 return hr;
477 static HRESULT create_server(REFCLSID rclsid, HANDLE *process)
479 static const WCHAR embeddingW[] = L" -Embedding";
480 HKEY key;
481 HRESULT hr;
482 WCHAR command[MAX_PATH + ARRAY_SIZE(embeddingW)];
483 DWORD size = (MAX_PATH+1) * sizeof(WCHAR);
484 STARTUPINFOW sinfo;
485 PROCESS_INFORMATION pinfo;
486 LONG ret;
488 hr = open_key_for_clsid(rclsid, L"LocalServer32", KEY_READ, &key);
489 if (FAILED(hr))
491 ERR("class %s not registered\n", debugstr_guid(rclsid));
492 return hr;
495 ret = RegQueryValueExW(key, NULL, NULL, NULL, (LPBYTE)command, &size);
496 RegCloseKey(key);
497 if (ret)
499 WARN("No default value for LocalServer32 key\n");
500 return REGDB_E_CLASSNOTREG; /* FIXME: check retval */
503 memset(&sinfo, 0, sizeof(sinfo));
504 sinfo.cb = sizeof(sinfo);
506 /* EXE servers are started with the -Embedding switch. */
508 lstrcatW(command, embeddingW);
510 TRACE("activating local server %s for %s\n", debugstr_w(command), debugstr_guid(rclsid));
512 /* FIXME: Win2003 supports a ServerExecutable value that is passed into
513 * CreateProcess */
514 if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &sinfo, &pinfo))
516 WARN("failed to run local server %s\n", debugstr_w(command));
517 return HRESULT_FROM_WIN32(GetLastError());
519 *process = pinfo.hProcess;
520 CloseHandle(pinfo.hThread);
522 return S_OK;
525 static HRESULT create_surrogate_server(REFCLSID rclsid, HANDLE *process)
527 static const WCHAR processidW[] = L" /PROCESSID:";
528 HKEY key;
529 int arch = (sizeof(void *) > sizeof(int)) ? 64 : 32;
530 REGSAM opposite = (arch == 64) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
531 BOOL is_wow64 = FALSE;
532 HRESULT hr;
533 WCHAR command[MAX_PATH + ARRAY_SIZE(processidW) + CHARS_IN_GUID];
534 DWORD size;
535 STARTUPINFOW si;
536 PROCESS_INFORMATION pi;
537 LONG ret;
539 TRACE("Attempting to start surrogate server for %s\n", debugstr_guid(rclsid));
541 hr = open_key_for_clsid(rclsid, NULL, KEY_READ, &key);
542 if (FAILED(hr) && (arch == 64 || (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
543 hr = open_key_for_clsid(rclsid, NULL, opposite | KEY_READ, &key);
544 if (FAILED(hr)) return hr;
545 RegCloseKey(key);
547 hr = open_appidkey_from_clsid(rclsid, KEY_READ, &key);
548 if (FAILED(hr) && (arch == 64 || (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
550 hr = open_appidkey_from_clsid(rclsid, opposite | KEY_READ, &key);
551 if (FAILED(hr)) return hr;
554 size = (MAX_PATH + 1) * sizeof(WCHAR);
555 ret = RegQueryValueExW(key, L"DllSurrogate", NULL, NULL, (LPBYTE)command, &size);
556 RegCloseKey(key);
557 if (ret || !size || !command[0])
559 TRACE("No value for DllSurrogate key\n");
561 if ((sizeof(void *) == 8 || is_wow64) && opposite == KEY_WOW64_32KEY)
562 GetSystemWow64DirectoryW(command, MAX_PATH - ARRAY_SIZE(L"\\dllhost.exe"));
563 else
564 GetSystemDirectoryW(command, MAX_PATH - ARRAY_SIZE(L"\\dllhost.exe"));
566 wcscat(command, L"\\dllhost.exe");
569 /* Surrogate EXE servers are started with the /PROCESSID:{GUID} switch. */
570 wcscat(command, processidW);
571 StringFromGUID2(rclsid, command + wcslen(command), CHARS_IN_GUID);
573 memset(&si, 0, sizeof(si));
574 si.cb = sizeof(si);
576 TRACE("Activating surrogate local server %s\n", debugstr_w(command));
578 if (is_wow64 && arch == 64)
580 void *cookie;
581 Wow64DisableWow64FsRedirection(&cookie);
582 if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
584 WARN("failed to run surrogate local server %s\n", debugstr_w(command));
585 hr = HRESULT_FROM_WIN32(GetLastError());
587 Wow64RevertWow64FsRedirection(cookie);
589 else if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
591 WARN("failed to run surrogate local server %s\n", debugstr_w(command));
592 hr = HRESULT_FROM_WIN32(GetLastError());
595 if (FAILED(hr)) return hr;
597 *process = pi.hProcess;
598 CloseHandle(pi.hThread);
600 return S_OK;
603 HRESULT rpc_get_local_class_object(REFCLSID rclsid, REFIID riid, void **obj)
605 PMInterfacePointer objref = NULL;
606 IServiceProvider *local_server;
607 IStream *stream = NULL;
608 ULARGE_INTEGER newpos;
609 LARGE_INTEGER seekto;
610 int tries = 0;
611 ULONG length;
612 HRESULT hr;
613 static const int MAXTRIES = 30; /* 30 seconds */
615 TRACE("clsid %s, riid %s\n", debugstr_guid(rclsid), debugstr_guid(riid));
617 while (tries++ < MAXTRIES)
619 DWORD index, start_ticks;
620 HANDLE process = 0;
622 if (SUCCEEDED(hr = rpcss_get_class_object(rclsid, &objref)))
623 break;
625 if (tries == 1)
627 if ((hr = create_local_service(rclsid)) && (hr = create_server(rclsid, &process)) &&
628 (hr = create_surrogate_server(rclsid, &process)) )
629 return hr;
632 /* Wait for one second, even if messages arrive. */
633 start_ticks = GetTickCount();
636 if (SUCCEEDED(CoWaitForMultipleHandles(0, 1000, (process != 0), &process, &index)) && process && !index)
638 WARN("Server for %s failed to start.\n", debugstr_guid(rclsid));
639 CloseHandle(process);
640 return E_NOINTERFACE;
642 } while (GetTickCount() - start_ticks < 1000);
644 if (process) CloseHandle(process);
647 if (!objref || tries >= MAXTRIES)
648 return E_NOINTERFACE;
650 if (SUCCEEDED(hr = CreateStreamOnHGlobal(0, TRUE, &stream)))
651 hr = IStream_Write(stream, objref->abData, objref->ulCntData, &length);
653 MIDL_user_free(objref);
655 if (SUCCEEDED(hr))
657 seekto.QuadPart = 0;
658 IStream_Seek(stream, seekto, STREAM_SEEK_SET, &newpos);
660 TRACE("Unmarshalling local server.\n");
661 hr = CoUnmarshalInterface(stream, &IID_IServiceProvider, (void **)&local_server);
662 if (SUCCEEDED(hr))
664 hr = IServiceProvider_QueryService(local_server, rclsid, riid, obj);
665 IServiceProvider_Release(local_server);
669 if (stream)
670 IStream_Release(stream);
672 return hr;
675 HRESULT rpc_register_local_server(REFCLSID clsid, IStream *stream, DWORD flags, unsigned int *cookie)
677 MInterfacePointer *obj;
678 const void *ptr;
679 HGLOBAL hmem;
680 SIZE_T size;
681 HRESULT hr;
683 TRACE("%s, %#lx\n", debugstr_guid(clsid), flags);
685 hr = GetHGlobalFromStream(stream, &hmem);
686 if (FAILED(hr)) return hr;
688 size = GlobalSize(hmem);
689 if (!(obj = heap_alloc(FIELD_OFFSET(MInterfacePointer, abData[size]))))
690 return E_OUTOFMEMORY;
691 obj->ulCntData = size;
692 ptr = GlobalLock(hmem);
693 memcpy(obj->abData, ptr, size);
694 GlobalUnlock(hmem);
696 hr = rpcss_server_register(clsid, flags, obj, cookie);
698 heap_free(obj);
700 return hr;
703 static HRESULT unmarshal_ORPCTHAT(RPC_MESSAGE *msg, ORPCTHAT *orpcthat, ORPC_EXTENT_ARRAY *orpc_ext_array,
704 WIRE_ORPC_EXTENT **first_wire_orpc_extent);
706 /* Channel Hook Functions */
708 static ULONG ChannelHooks_ClientGetSize(SChannelHookCallInfo *info, struct channel_hook_buffer_data **data,
709 unsigned int *hook_count, ULONG *extension_count)
711 struct channel_hook_entry *entry;
712 ULONG total_size = 0;
713 unsigned int hook_index = 0;
715 *hook_count = 0;
716 *extension_count = 0;
718 EnterCriticalSection(&csChannelHook);
720 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
721 (*hook_count)++;
723 if (*hook_count)
724 *data = HeapAlloc(GetProcessHeap(), 0, *hook_count * sizeof(struct channel_hook_buffer_data));
725 else
726 *data = NULL;
728 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
730 ULONG extension_size = 0;
732 IChannelHook_ClientGetSize(entry->hook, &entry->id, &info->iid, &extension_size);
734 TRACE("%s: extension_size = %lu\n", debugstr_guid(&entry->id), extension_size);
736 extension_size = (extension_size+7)&~7;
737 (*data)[hook_index].id = entry->id;
738 (*data)[hook_index].extension_size = extension_size;
740 /* an extension is only put onto the wire if it has data to write */
741 if (extension_size)
743 total_size += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[extension_size]);
744 (*extension_count)++;
747 hook_index++;
750 LeaveCriticalSection(&csChannelHook);
752 return total_size;
755 static unsigned char * ChannelHooks_ClientFillBuffer(SChannelHookCallInfo *info,
756 unsigned char *buffer, struct channel_hook_buffer_data *data,
757 unsigned int hook_count)
759 struct channel_hook_entry *entry;
761 EnterCriticalSection(&csChannelHook);
763 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
765 unsigned int i;
766 ULONG extension_size = 0;
767 WIRE_ORPC_EXTENT *wire_orpc_extent = (WIRE_ORPC_EXTENT *)buffer;
769 for (i = 0; i < hook_count; i++)
770 if (IsEqualGUID(&entry->id, &data[i].id))
771 extension_size = data[i].extension_size;
773 /* an extension is only put onto the wire if it has data to write */
774 if (!extension_size)
775 continue;
777 IChannelHook_ClientFillBuffer(entry->hook, &entry->id, &info->iid,
778 &extension_size, buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]));
780 TRACE("%s: extension_size = %lu\n", debugstr_guid(&entry->id), extension_size);
782 /* FIXME: set unused portion of wire_orpc_extent->data to 0? */
784 wire_orpc_extent->conformance = (extension_size+7)&~7;
785 wire_orpc_extent->size = extension_size;
786 wire_orpc_extent->id = entry->id;
787 buffer += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[wire_orpc_extent->conformance]);
790 LeaveCriticalSection(&csChannelHook);
792 return buffer;
795 static void ChannelHooks_ServerNotify(SChannelHookCallInfo *info,
796 DWORD lDataRep, WIRE_ORPC_EXTENT *first_wire_orpc_extent,
797 ULONG extension_count)
799 struct channel_hook_entry *entry;
800 ULONG i;
802 EnterCriticalSection(&csChannelHook);
804 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
806 WIRE_ORPC_EXTENT *wire_orpc_extent;
807 for (i = 0, wire_orpc_extent = first_wire_orpc_extent;
808 i < extension_count;
809 i++, wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance])
811 if (IsEqualGUID(&entry->id, &wire_orpc_extent->id))
812 break;
814 if (i == extension_count) wire_orpc_extent = NULL;
816 IChannelHook_ServerNotify(entry->hook, &entry->id, &info->iid,
817 wire_orpc_extent ? wire_orpc_extent->size : 0,
818 wire_orpc_extent ? wire_orpc_extent->data : NULL,
819 lDataRep);
822 LeaveCriticalSection(&csChannelHook);
825 static ULONG ChannelHooks_ServerGetSize(SChannelHookCallInfo *info,
826 struct channel_hook_buffer_data **data, unsigned int *hook_count,
827 ULONG *extension_count)
829 struct channel_hook_entry *entry;
830 ULONG total_size = 0;
831 unsigned int hook_index = 0;
833 *hook_count = 0;
834 *extension_count = 0;
836 EnterCriticalSection(&csChannelHook);
838 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
839 (*hook_count)++;
841 if (*hook_count)
842 *data = HeapAlloc(GetProcessHeap(), 0, *hook_count * sizeof(struct channel_hook_buffer_data));
843 else
844 *data = NULL;
846 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
848 ULONG extension_size = 0;
850 IChannelHook_ServerGetSize(entry->hook, &entry->id, &info->iid, S_OK,
851 &extension_size);
853 TRACE("%s: extension_size = %lu\n", debugstr_guid(&entry->id), extension_size);
855 extension_size = (extension_size+7)&~7;
856 (*data)[hook_index].id = entry->id;
857 (*data)[hook_index].extension_size = extension_size;
859 /* an extension is only put onto the wire if it has data to write */
860 if (extension_size)
862 total_size += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[extension_size]);
863 (*extension_count)++;
866 hook_index++;
869 LeaveCriticalSection(&csChannelHook);
871 return total_size;
874 static unsigned char * ChannelHooks_ServerFillBuffer(SChannelHookCallInfo *info,
875 unsigned char *buffer, struct channel_hook_buffer_data *data,
876 unsigned int hook_count)
878 struct channel_hook_entry *entry;
880 EnterCriticalSection(&csChannelHook);
882 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
884 unsigned int i;
885 ULONG extension_size = 0;
886 WIRE_ORPC_EXTENT *wire_orpc_extent = (WIRE_ORPC_EXTENT *)buffer;
888 for (i = 0; i < hook_count; i++)
889 if (IsEqualGUID(&entry->id, &data[i].id))
890 extension_size = data[i].extension_size;
892 /* an extension is only put onto the wire if it has data to write */
893 if (!extension_size)
894 continue;
896 IChannelHook_ServerFillBuffer(entry->hook, &entry->id, &info->iid,
897 &extension_size, buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]),
898 S_OK);
900 TRACE("%s: extension_size = %lu\n", debugstr_guid(&entry->id), extension_size);
902 /* FIXME: set unused portion of wire_orpc_extent->data to 0? */
904 wire_orpc_extent->conformance = (extension_size+7)&~7;
905 wire_orpc_extent->size = extension_size;
906 wire_orpc_extent->id = entry->id;
907 buffer += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[wire_orpc_extent->conformance]);
910 LeaveCriticalSection(&csChannelHook);
912 return buffer;
915 static void ChannelHooks_ClientNotify(SChannelHookCallInfo *info,
916 DWORD lDataRep, WIRE_ORPC_EXTENT *first_wire_orpc_extent,
917 ULONG extension_count, HRESULT hrFault)
919 struct channel_hook_entry *entry;
920 ULONG i;
922 EnterCriticalSection(&csChannelHook);
924 LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
926 WIRE_ORPC_EXTENT *wire_orpc_extent;
927 for (i = 0, wire_orpc_extent = first_wire_orpc_extent;
928 i < extension_count;
929 i++, wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance])
931 if (IsEqualGUID(&entry->id, &wire_orpc_extent->id))
932 break;
934 if (i == extension_count) wire_orpc_extent = NULL;
936 IChannelHook_ClientNotify(entry->hook, &entry->id, &info->iid,
937 wire_orpc_extent ? wire_orpc_extent->size : 0,
938 wire_orpc_extent ? wire_orpc_extent->data : NULL,
939 lDataRep, hrFault);
942 LeaveCriticalSection(&csChannelHook);
945 HRESULT rpc_register_channel_hook(REFGUID rguid, IChannelHook *hook)
947 struct channel_hook_entry *entry;
949 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
950 if (!entry)
951 return E_OUTOFMEMORY;
953 entry->id = *rguid;
954 entry->hook = hook;
955 IChannelHook_AddRef(hook);
957 EnterCriticalSection(&csChannelHook);
958 list_add_tail(&channel_hooks, &entry->entry);
959 LeaveCriticalSection(&csChannelHook);
961 return S_OK;
964 void rpc_unregister_channel_hooks(void)
966 struct channel_hook_entry *cursor;
967 struct channel_hook_entry *cursor2;
969 EnterCriticalSection(&csChannelHook);
970 LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &channel_hooks, struct channel_hook_entry, entry)
971 HeapFree(GetProcessHeap(), 0, cursor);
972 LeaveCriticalSection(&csChannelHook);
973 DeleteCriticalSection(&csChannelHook);
974 DeleteCriticalSection(&csRegIf);
977 /* RPC Channel Buffer Functions */
979 static HRESULT WINAPI RpcChannelBuffer_QueryInterface(IRpcChannelBuffer *iface, REFIID riid, LPVOID *ppv)
981 *ppv = NULL;
982 if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown))
984 *ppv = iface;
985 IRpcChannelBuffer_AddRef(iface);
986 return S_OK;
988 return E_NOINTERFACE;
991 static ULONG WINAPI RpcChannelBuffer_AddRef(LPRPCCHANNELBUFFER iface)
993 RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
994 return InterlockedIncrement(&This->refs);
997 static ULONG WINAPI ServerRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface)
999 RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
1000 ULONG ref;
1002 ref = InterlockedDecrement(&This->refs);
1003 if (ref)
1004 return ref;
1006 HeapFree(GetProcessHeap(), 0, This);
1007 return 0;
1010 static ULONG WINAPI ClientRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface)
1012 ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
1013 ULONG ref;
1015 ref = InterlockedDecrement(&This->super.refs);
1016 if (ref)
1017 return ref;
1019 if (This->event) CloseHandle(This->event);
1020 RpcBindingFree(&This->bind);
1021 HeapFree(GetProcessHeap(), 0, This);
1022 return 0;
1025 static HRESULT WINAPI ServerRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
1027 RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
1028 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
1029 RPC_STATUS status;
1030 ORPCTHAT *orpcthat;
1031 struct message_state *message_state;
1032 ULONG extensions_size;
1033 struct channel_hook_buffer_data *channel_hook_data;
1034 unsigned int channel_hook_count;
1035 ULONG extension_count;
1037 TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid));
1039 message_state = msg->Handle;
1040 /* restore the binding handle and the real start of data */
1041 msg->Handle = message_state->binding_handle;
1042 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
1044 extensions_size = ChannelHooks_ServerGetSize(&message_state->channel_hook_info,
1045 &channel_hook_data, &channel_hook_count, &extension_count);
1047 msg->BufferLength += FIELD_OFFSET(WIRE_ORPCTHAT, extensions) + sizeof(DWORD);
1048 if (extensions_size)
1050 msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent[2*sizeof(DWORD) + extensions_size]);
1051 if (extension_count & 1)
1052 msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
1055 if (message_state->bypass_rpcrt)
1057 msg->Buffer = HeapAlloc(GetProcessHeap(), 0, msg->BufferLength);
1058 if (msg->Buffer)
1059 status = RPC_S_OK;
1060 else
1062 HeapFree(GetProcessHeap(), 0, channel_hook_data);
1063 return E_OUTOFMEMORY;
1066 else
1067 status = I_RpcGetBuffer(msg);
1069 orpcthat = msg->Buffer;
1070 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPCTHAT, extensions);
1072 orpcthat->flags = ORPCF_NULL /* FIXME? */;
1074 /* NDR representation of orpcthat->extensions */
1075 *(DWORD *)msg->Buffer = extensions_size ? 1 : 0;
1076 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
1078 if (extensions_size)
1080 WIRE_ORPC_EXTENT_ARRAY *orpc_extent_array = msg->Buffer;
1081 orpc_extent_array->size = extension_count;
1082 orpc_extent_array->reserved = 0;
1083 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent);
1084 /* NDR representation of orpc_extent_array->extent */
1085 *(DWORD *)msg->Buffer = 1;
1086 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
1087 /* NDR representation of [size_is] attribute of orpc_extent_array->extent */
1088 *(DWORD *)msg->Buffer = (extension_count + 1) & ~1;
1089 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
1091 msg->Buffer = ChannelHooks_ServerFillBuffer(&message_state->channel_hook_info,
1092 msg->Buffer, channel_hook_data, channel_hook_count);
1094 /* we must add a dummy extension if there is an odd extension
1095 * count to meet the contract specified by the size_is attribute */
1096 if (extension_count & 1)
1098 WIRE_ORPC_EXTENT *wire_orpc_extent = msg->Buffer;
1099 wire_orpc_extent->conformance = 0;
1100 wire_orpc_extent->id = GUID_NULL;
1101 wire_orpc_extent->size = 0;
1102 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
1106 HeapFree(GetProcessHeap(), 0, channel_hook_data);
1108 /* store the prefixed data length so that we can restore the real buffer
1109 * later */
1110 message_state->prefix_data_len = (char *)msg->Buffer - (char *)orpcthat;
1111 msg->BufferLength -= message_state->prefix_data_len;
1112 /* save away the message state again */
1113 msg->Handle = message_state;
1115 TRACE("-- %ld\n", status);
1117 return HRESULT_FROM_WIN32(status);
1120 static HANDLE ClientRpcChannelBuffer_GetEventHandle(ClientRpcChannelBuffer *This)
1122 HANDLE event = InterlockedExchangePointer(&This->event, NULL);
1124 /* Note: must be auto-reset event so we can reuse it without a call
1125 * to ResetEvent */
1126 if (!event) event = CreateEventW(NULL, FALSE, FALSE, NULL);
1128 return event;
1131 static void ClientRpcChannelBuffer_ReleaseEventHandle(ClientRpcChannelBuffer *This, HANDLE event)
1133 if (InterlockedCompareExchangePointer(&This->event, event, NULL))
1134 /* already a handle cached in This */
1135 CloseHandle(event);
1138 static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
1140 ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
1141 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
1142 RPC_CLIENT_INTERFACE *cif;
1143 RPC_STATUS status;
1144 ORPCTHIS *orpcthis;
1145 struct message_state *message_state;
1146 ULONG extensions_size;
1147 struct channel_hook_buffer_data *channel_hook_data;
1148 unsigned int channel_hook_count;
1149 ULONG extension_count;
1150 IPID ipid;
1151 HRESULT hr;
1152 struct apartment *apt = NULL;
1154 TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid));
1156 cif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_CLIENT_INTERFACE));
1157 if (!cif)
1158 return E_OUTOFMEMORY;
1160 message_state = HeapAlloc(GetProcessHeap(), 0, sizeof(*message_state));
1161 if (!message_state)
1163 HeapFree(GetProcessHeap(), 0, cif);
1164 return E_OUTOFMEMORY;
1167 cif->Length = sizeof(RPC_CLIENT_INTERFACE);
1168 /* RPC interface ID = COM interface ID */
1169 cif->InterfaceId.SyntaxGUID = This->iid;
1170 /* COM objects always have a version of 0.0 */
1171 cif->InterfaceId.SyntaxVersion.MajorVersion = 0;
1172 cif->InterfaceId.SyntaxVersion.MinorVersion = 0;
1173 msg->Handle = This->bind;
1174 msg->RpcInterfaceInformation = cif;
1176 message_state->prefix_data_len = 0;
1177 message_state->binding_handle = This->bind;
1179 message_state->channel_hook_info.iid = *riid;
1180 message_state->channel_hook_info.cbSize = sizeof(message_state->channel_hook_info);
1181 CoGetCurrentLogicalThreadId(&message_state->channel_hook_info.uCausality);
1182 message_state->channel_hook_info.dwServerPid = This->server_pid;
1183 message_state->channel_hook_info.iMethod = msg->ProcNum & ~RPC_FLAGS_VALID_BIT;
1184 message_state->channel_hook_info.pObject = NULL; /* only present on server-side */
1185 message_state->target_hwnd = NULL;
1186 message_state->target_tid = 0;
1187 memset(&message_state->params, 0, sizeof(message_state->params));
1189 extensions_size = ChannelHooks_ClientGetSize(&message_state->channel_hook_info,
1190 &channel_hook_data, &channel_hook_count, &extension_count);
1192 msg->BufferLength += FIELD_OFFSET(WIRE_ORPCTHIS, extensions) + sizeof(DWORD);
1193 if (extensions_size)
1195 msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent[2*sizeof(DWORD) + extensions_size]);
1196 if (extension_count & 1)
1197 msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
1200 RpcBindingInqObject(message_state->binding_handle, &ipid);
1201 hr = ipid_get_dispatch_params(&ipid, &apt, NULL, &message_state->params.stub,
1202 &message_state->params.chan,
1203 &message_state->params.iid,
1204 &message_state->params.iface);
1205 if (hr == S_OK)
1207 /* stub, chan, iface and iid are unneeded in multi-threaded case as we go
1208 * via the RPC runtime */
1209 if (apt->multi_threaded)
1211 IRpcStubBuffer_Release(message_state->params.stub);
1212 message_state->params.stub = NULL;
1213 IRpcChannelBuffer_Release(message_state->params.chan);
1214 message_state->params.chan = NULL;
1215 message_state->params.iface = NULL;
1217 else
1219 message_state->params.bypass_rpcrt = TRUE;
1220 message_state->target_hwnd = apartment_getwindow(apt);
1221 message_state->target_tid = apt->tid;
1222 /* we assume later on that this being non-NULL is the indicator that
1223 * means call directly instead of going through RPC runtime */
1224 if (!message_state->target_hwnd)
1225 ERR("window for apartment %s is NULL\n", wine_dbgstr_longlong(apt->oxid));
1228 if (apt) apartment_release(apt);
1229 message_state->params.handle = ClientRpcChannelBuffer_GetEventHandle(This);
1230 /* Note: message_state->params.msg is initialised in
1231 * ClientRpcChannelBuffer_SendReceive */
1233 /* shortcut the RPC runtime */
1234 if (message_state->target_hwnd)
1236 msg->Buffer = HeapAlloc(GetProcessHeap(), 0, msg->BufferLength);
1237 if (msg->Buffer)
1238 status = RPC_S_OK;
1239 else
1240 status = ERROR_OUTOFMEMORY;
1242 else
1243 status = I_RpcGetBuffer(msg);
1245 msg->Handle = message_state;
1247 if (status == RPC_S_OK)
1249 orpcthis = msg->Buffer;
1250 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPCTHIS, extensions);
1252 orpcthis->version.MajorVersion = COM_MAJOR_VERSION;
1253 orpcthis->version.MinorVersion = COM_MINOR_VERSION;
1254 orpcthis->flags = message_state->channel_hook_info.dwServerPid ? ORPCF_LOCAL : ORPCF_NULL;
1255 orpcthis->reserved1 = 0;
1256 orpcthis->cid = message_state->channel_hook_info.uCausality;
1258 /* NDR representation of orpcthis->extensions */
1259 *(DWORD *)msg->Buffer = extensions_size ? 1 : 0;
1260 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
1262 if (extensions_size)
1264 ORPC_EXTENT_ARRAY *orpc_extent_array = msg->Buffer;
1265 orpc_extent_array->size = extension_count;
1266 orpc_extent_array->reserved = 0;
1267 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent);
1268 /* NDR representation of orpc_extent_array->extent */
1269 *(DWORD *)msg->Buffer = 1;
1270 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
1271 /* NDR representation of [size_is] attribute of orpc_extent_array->extent */
1272 *(DWORD *)msg->Buffer = (extension_count + 1) & ~1;
1273 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
1275 msg->Buffer = ChannelHooks_ClientFillBuffer(&message_state->channel_hook_info,
1276 msg->Buffer, channel_hook_data, channel_hook_count);
1278 /* we must add a dummy extension if there is an odd extension
1279 * count to meet the contract specified by the size_is attribute */
1280 if (extension_count & 1)
1282 WIRE_ORPC_EXTENT *wire_orpc_extent = msg->Buffer;
1283 wire_orpc_extent->conformance = 0;
1284 wire_orpc_extent->id = GUID_NULL;
1285 wire_orpc_extent->size = 0;
1286 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
1290 /* store the prefixed data length so that we can restore the real buffer
1291 * pointer in ClientRpcChannelBuffer_SendReceive. */
1292 message_state->prefix_data_len = (char *)msg->Buffer - (char *)orpcthis;
1293 msg->BufferLength -= message_state->prefix_data_len;
1296 HeapFree(GetProcessHeap(), 0, channel_hook_data);
1298 TRACE("-- %ld\n", status);
1300 return HRESULT_FROM_WIN32(status);
1303 static HRESULT WINAPI ServerRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus)
1305 FIXME("stub\n");
1306 return E_NOTIMPL;
1309 /* this thread runs an outgoing RPC */
1310 static DWORD WINAPI rpc_sendreceive_thread(LPVOID param)
1312 struct dispatch_params *data = param;
1314 /* Note: I_RpcSendReceive doesn't raise exceptions like the higher-level
1315 * RPC functions do */
1316 data->status = I_RpcSendReceive((RPC_MESSAGE *)data->msg);
1318 TRACE("completed with status %#lx\n", data->status);
1320 SetEvent(data->handle);
1322 return 0;
1325 static inline HRESULT ClientRpcChannelBuffer_IsCorrectApartment(ClientRpcChannelBuffer *This, const struct apartment *apt)
1327 if (!apt)
1328 return S_FALSE;
1329 if (This->oxid != apartment_getoxid(apt))
1330 return S_FALSE;
1331 return S_OK;
1334 static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus)
1336 ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
1337 HRESULT hr;
1338 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
1339 RPC_STATUS status;
1340 DWORD index;
1341 struct message_state *message_state;
1342 ORPCTHAT orpcthat;
1343 ORPC_EXTENT_ARRAY orpc_ext_array;
1344 WIRE_ORPC_EXTENT *first_wire_orpc_extent = NULL;
1345 HRESULT hrFault = S_OK;
1346 struct apartment *apt = apartment_get_current_or_mta();
1347 struct tlsdata *tlsdata;
1349 TRACE("%p, iMethod %ld\n", olemsg, olemsg->iMethod);
1351 hr = ClientRpcChannelBuffer_IsCorrectApartment(This, apt);
1352 if (hr != S_OK)
1354 ERR("called from wrong apartment, should have been 0x%s\n",
1355 wine_dbgstr_longlong(This->oxid));
1356 if (apt) apartment_release(apt);
1357 return RPC_E_WRONG_THREAD;
1360 if (FAILED(hr = com_get_tlsdata(&tlsdata)))
1361 return hr;
1363 /* This situation should be impossible in multi-threaded apartments,
1364 * because the calling thread isn't re-enterable.
1365 * Note: doing a COM call during the processing of a sent message is
1366 * only disallowed if a client call is already being waited for
1367 * completion */
1368 if (!apt->multi_threaded &&
1369 tlsdata->pending_call_count_client &&
1370 InSendMessage())
1372 ERR("can't make an outgoing COM call in response to a sent message\n");
1373 apartment_release(apt);
1374 return RPC_E_CANTCALLOUT_ININPUTSYNCCALL;
1377 message_state = msg->Handle;
1378 /* restore the binding handle and the real start of data */
1379 msg->Handle = message_state->binding_handle;
1380 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
1381 msg->BufferLength += message_state->prefix_data_len;
1383 /* Note: this is an optimization in the Microsoft OLE runtime that we need
1384 * to copy, as shown by the test_no_couninitialize_client test. without
1385 * short-circuiting the RPC runtime in the case below, the test will
1386 * deadlock on the loader lock due to the RPC runtime needing to create
1387 * a thread to process the RPC when this function is called indirectly
1388 * from DllMain */
1390 message_state->params.msg = olemsg;
1391 if (message_state->params.bypass_rpcrt)
1393 TRACE("Calling apartment thread %#lx...\n", message_state->target_tid);
1395 msg->ProcNum &= ~RPC_FLAGS_VALID_BIT;
1397 if (!PostMessageW(message_state->target_hwnd, DM_EXECUTERPC, 0,
1398 (LPARAM)&message_state->params))
1400 ERR("PostMessage failed with error %lu\n", GetLastError());
1402 /* Note: message_state->params.iface doesn't have a reference and
1403 * so doesn't need to be released */
1405 hr = HRESULT_FROM_WIN32(GetLastError());
1408 else
1410 /* we use a separate thread here because we need to be able to
1411 * pump the message loop in the application thread: if we do not,
1412 * any windows created by this thread will hang and RPCs that try
1413 * and re-enter this STA from an incoming server thread will
1414 * deadlock. InstallShield is an example of that.
1416 if (!QueueUserWorkItem(rpc_sendreceive_thread, &message_state->params, WT_EXECUTEDEFAULT))
1418 ERR("QueueUserWorkItem failed with error %lu\n", GetLastError());
1419 hr = E_UNEXPECTED;
1421 else
1422 hr = S_OK;
1425 if (hr == S_OK)
1427 if (WaitForSingleObject(message_state->params.handle, 0))
1429 tlsdata->pending_call_count_client++;
1430 hr = CoWaitForMultipleHandles(0, INFINITE, 1, &message_state->params.handle, &index);
1431 tlsdata->pending_call_count_client--;
1434 ClientRpcChannelBuffer_ReleaseEventHandle(This, message_state->params.handle);
1436 /* for WM shortcut, faults are returned in params->hr */
1437 if (hr == S_OK)
1438 hrFault = message_state->params.hr;
1440 status = message_state->params.status;
1442 orpcthat.flags = ORPCF_NULL;
1443 orpcthat.extensions = NULL;
1445 TRACE("RPC call status: %#lx\n", status);
1446 if (status != RPC_S_OK)
1447 hr = HRESULT_FROM_WIN32(status);
1449 TRACE("hrFault = %#lx\n", hrFault);
1451 /* FIXME: this condition should be
1452 * "hr == S_OK && (!hrFault || msg->BufferLength > FIELD_OFFSET(ORPCTHAT, extensions) + 4)"
1453 * but we don't currently reset the message length for PostMessage
1454 * dispatched calls */
1455 if (hr == S_OK && hrFault == S_OK)
1457 HRESULT hr2;
1458 char *original_buffer = msg->Buffer;
1460 /* handle ORPCTHAT and client extensions */
1462 hr2 = unmarshal_ORPCTHAT(msg, &orpcthat, &orpc_ext_array, &first_wire_orpc_extent);
1463 if (FAILED(hr2))
1464 hr = hr2;
1466 message_state->prefix_data_len = (char *)msg->Buffer - original_buffer;
1467 msg->BufferLength -= message_state->prefix_data_len;
1469 else
1470 message_state->prefix_data_len = 0;
1472 if (hr == S_OK)
1474 ChannelHooks_ClientNotify(&message_state->channel_hook_info,
1475 msg->DataRepresentation,
1476 first_wire_orpc_extent,
1477 orpcthat.extensions && first_wire_orpc_extent ? orpcthat.extensions->size : 0,
1478 hrFault);
1481 /* save away the message state again */
1482 msg->Handle = message_state;
1484 if (pstatus) *pstatus = status;
1486 if (hr == S_OK)
1487 hr = hrFault;
1489 TRACE("-- %#lx\n", hr);
1491 apartment_release(apt);
1492 return hr;
1495 static HRESULT WINAPI ServerRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
1497 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
1498 RPC_STATUS status;
1499 struct message_state *message_state;
1501 TRACE("(%p)\n", msg);
1503 message_state = msg->Handle;
1504 /* restore the binding handle and the real start of data */
1505 msg->Handle = message_state->binding_handle;
1506 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
1507 msg->BufferLength += message_state->prefix_data_len;
1508 message_state->prefix_data_len = 0;
1510 if (message_state->bypass_rpcrt)
1512 HeapFree(GetProcessHeap(), 0, msg->Buffer);
1513 status = RPC_S_OK;
1515 else
1516 status = I_RpcFreeBuffer(msg);
1518 msg->Handle = message_state;
1520 TRACE("-- %ld\n", status);
1522 return HRESULT_FROM_WIN32(status);
1525 static HRESULT WINAPI ClientRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
1527 RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
1528 RPC_STATUS status;
1529 struct message_state *message_state;
1531 TRACE("(%p)\n", msg);
1533 message_state = msg->Handle;
1534 /* restore the binding handle and the real start of data */
1535 msg->Handle = message_state->binding_handle;
1536 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
1537 msg->BufferLength += message_state->prefix_data_len;
1539 if (message_state->params.bypass_rpcrt)
1541 HeapFree(GetProcessHeap(), 0, msg->Buffer);
1542 status = RPC_S_OK;
1544 else
1545 status = I_RpcFreeBuffer(msg);
1547 HeapFree(GetProcessHeap(), 0, msg->RpcInterfaceInformation);
1548 msg->RpcInterfaceInformation = NULL;
1550 if (message_state->params.stub)
1551 IRpcStubBuffer_Release(message_state->params.stub);
1552 if (message_state->params.chan)
1553 IRpcChannelBuffer_Release(message_state->params.chan);
1554 HeapFree(GetProcessHeap(), 0, message_state);
1556 TRACE("-- %ld\n", status);
1558 return HRESULT_FROM_WIN32(status);
1561 static HRESULT WINAPI ClientRpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext)
1563 ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
1565 TRACE("(%p,%p)\n", pdwDestContext, ppvDestContext);
1567 *pdwDestContext = This->super.dest_context;
1568 *ppvDestContext = This->super.dest_context_data;
1570 return S_OK;
1573 static HRESULT WINAPI ServerRpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* dest_context, void** dest_context_data)
1575 RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
1577 TRACE("(%p,%p)\n", dest_context, dest_context_data);
1579 *dest_context = This->dest_context;
1580 *dest_context_data = This->dest_context_data;
1581 return S_OK;
1584 static HRESULT WINAPI RpcChannelBuffer_IsConnected(LPRPCCHANNELBUFFER iface)
1586 TRACE("()\n");
1587 /* native does nothing too */
1588 return S_OK;
1591 static const IRpcChannelBufferVtbl ClientRpcChannelBufferVtbl =
1593 RpcChannelBuffer_QueryInterface,
1594 RpcChannelBuffer_AddRef,
1595 ClientRpcChannelBuffer_Release,
1596 ClientRpcChannelBuffer_GetBuffer,
1597 ClientRpcChannelBuffer_SendReceive,
1598 ClientRpcChannelBuffer_FreeBuffer,
1599 ClientRpcChannelBuffer_GetDestCtx,
1600 RpcChannelBuffer_IsConnected
1603 static const IRpcChannelBufferVtbl ServerRpcChannelBufferVtbl =
1605 RpcChannelBuffer_QueryInterface,
1606 RpcChannelBuffer_AddRef,
1607 ServerRpcChannelBuffer_Release,
1608 ServerRpcChannelBuffer_GetBuffer,
1609 ServerRpcChannelBuffer_SendReceive,
1610 ServerRpcChannelBuffer_FreeBuffer,
1611 ServerRpcChannelBuffer_GetDestCtx,
1612 RpcChannelBuffer_IsConnected
1615 /* returns a channel buffer for proxies */
1616 HRESULT rpc_create_clientchannel(const OXID *oxid, const IPID *ipid,
1617 const OXID_INFO *oxid_info, const IID *iid,
1618 DWORD dest_context, void *dest_context_data,
1619 IRpcChannelBuffer **chan, struct apartment *apt)
1621 ClientRpcChannelBuffer *This;
1622 WCHAR endpoint[200];
1623 RPC_BINDING_HANDLE bind;
1624 RPC_STATUS status;
1625 LPWSTR string_binding;
1627 /* FIXME: get the endpoint from oxid_info->psa instead */
1628 get_rpc_endpoint(endpoint, oxid);
1630 TRACE("proxy pipe: connecting to endpoint: %s\n", debugstr_w(endpoint));
1632 status = RpcStringBindingComposeW(
1633 NULL,
1634 rpctransportW,
1635 NULL,
1636 endpoint,
1637 NULL,
1638 &string_binding);
1640 if (status == RPC_S_OK)
1642 status = RpcBindingFromStringBindingW(string_binding, &bind);
1644 if (status == RPC_S_OK)
1646 IPID ipid2 = *ipid; /* why can't RpcBindingSetObject take a const? */
1647 status = RpcBindingSetObject(bind, &ipid2);
1648 if (status != RPC_S_OK)
1649 RpcBindingFree(&bind);
1652 RpcStringFreeW(&string_binding);
1655 if (status != RPC_S_OK)
1657 ERR("Couldn't get binding for endpoint %s, status = %ld\n", debugstr_w(endpoint), status);
1658 return HRESULT_FROM_WIN32(status);
1661 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1662 if (!This)
1664 RpcBindingFree(&bind);
1665 return E_OUTOFMEMORY;
1668 This->super.IRpcChannelBuffer_iface.lpVtbl = &ClientRpcChannelBufferVtbl;
1669 This->super.refs = 1;
1670 This->super.dest_context = dest_context;
1671 This->super.dest_context_data = dest_context_data;
1672 This->bind = bind;
1673 This->oxid = apartment_getoxid(apt);
1674 This->server_pid = oxid_info->dwPid;
1675 This->event = NULL;
1676 This->iid = *iid;
1678 *chan = &This->super.IRpcChannelBuffer_iface;
1680 return S_OK;
1683 HRESULT rpc_create_serverchannel(DWORD dest_context, void *dest_context_data, IRpcChannelBuffer **chan)
1685 RpcChannelBuffer *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1686 if (!This)
1687 return E_OUTOFMEMORY;
1689 This->IRpcChannelBuffer_iface.lpVtbl = &ServerRpcChannelBufferVtbl;
1690 This->refs = 1;
1691 This->dest_context = dest_context;
1692 This->dest_context_data = dest_context_data;
1694 *chan = &This->IRpcChannelBuffer_iface;
1696 return S_OK;
1699 /* unmarshals ORPC_EXTENT_ARRAY according to NDR rules, but doesn't allocate
1700 * any memory */
1701 static HRESULT unmarshal_ORPC_EXTENT_ARRAY(RPC_MESSAGE *msg, const char *end,
1702 ORPC_EXTENT_ARRAY *extensions,
1703 WIRE_ORPC_EXTENT **first_wire_orpc_extent)
1705 DWORD pointer_id;
1706 DWORD i;
1708 memcpy(extensions, msg->Buffer, FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent));
1709 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent);
1711 if ((const char *)msg->Buffer + 2 * sizeof(DWORD) > end)
1712 return RPC_E_INVALID_HEADER;
1714 pointer_id = *(DWORD *)msg->Buffer;
1715 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
1716 extensions->extent = NULL;
1718 if (pointer_id)
1720 WIRE_ORPC_EXTENT *wire_orpc_extent;
1722 /* conformance */
1723 if (*(DWORD *)msg->Buffer != ((extensions->size+1)&~1))
1724 return RPC_S_INVALID_BOUND;
1726 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
1728 /* arbitrary limit for security (don't know what native does) */
1729 if (extensions->size > 256)
1731 ERR("too many extensions: %ld\n", extensions->size);
1732 return RPC_S_INVALID_BOUND;
1735 *first_wire_orpc_extent = wire_orpc_extent = msg->Buffer;
1736 for (i = 0; i < ((extensions->size+1)&~1); i++)
1738 if ((const char *)&wire_orpc_extent->data[0] > end)
1739 return RPC_S_INVALID_BOUND;
1740 if (wire_orpc_extent->conformance != ((wire_orpc_extent->size+7)&~7))
1741 return RPC_S_INVALID_BOUND;
1742 if ((const char *)&wire_orpc_extent->data[wire_orpc_extent->conformance] > end)
1743 return RPC_S_INVALID_BOUND;
1744 TRACE("size %lu, guid %s\n", wire_orpc_extent->size, debugstr_guid(&wire_orpc_extent->id));
1745 wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance];
1747 msg->Buffer = wire_orpc_extent;
1750 return S_OK;
1753 /* unmarshals ORPCTHIS according to NDR rules, but doesn't allocate any memory */
1754 static HRESULT unmarshal_ORPCTHIS(RPC_MESSAGE *msg, ORPCTHIS *orpcthis,
1755 ORPC_EXTENT_ARRAY *orpc_ext_array, WIRE_ORPC_EXTENT **first_wire_orpc_extent)
1757 const char *end = (char *)msg->Buffer + msg->BufferLength;
1759 *first_wire_orpc_extent = NULL;
1761 if (msg->BufferLength < FIELD_OFFSET(WIRE_ORPCTHIS, extensions) + sizeof(DWORD))
1763 ERR("invalid buffer length\n");
1764 return RPC_E_INVALID_HEADER;
1767 memcpy(orpcthis, msg->Buffer, FIELD_OFFSET(WIRE_ORPCTHIS, extensions));
1768 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPCTHIS, extensions);
1770 if ((const char *)msg->Buffer + sizeof(DWORD) > end)
1771 return RPC_E_INVALID_HEADER;
1773 if (*(DWORD *)msg->Buffer)
1774 orpcthis->extensions = orpc_ext_array;
1775 else
1776 orpcthis->extensions = NULL;
1778 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
1780 if (orpcthis->extensions)
1782 HRESULT hr = unmarshal_ORPC_EXTENT_ARRAY(msg, end, orpc_ext_array,
1783 first_wire_orpc_extent);
1784 if (FAILED(hr))
1785 return hr;
1788 if ((orpcthis->version.MajorVersion != COM_MAJOR_VERSION) ||
1789 (orpcthis->version.MinorVersion > COM_MINOR_VERSION))
1791 ERR("COM version {%d, %d} not supported\n",
1792 orpcthis->version.MajorVersion, orpcthis->version.MinorVersion);
1793 return RPC_E_VERSION_MISMATCH;
1796 if (orpcthis->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4))
1798 ERR("invalid flags %#lx\n", orpcthis->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4));
1799 return RPC_E_INVALID_HEADER;
1802 return S_OK;
1805 static HRESULT unmarshal_ORPCTHAT(RPC_MESSAGE *msg, ORPCTHAT *orpcthat,
1806 ORPC_EXTENT_ARRAY *orpc_ext_array, WIRE_ORPC_EXTENT **first_wire_orpc_extent)
1808 const char *end = (char *)msg->Buffer + msg->BufferLength;
1810 *first_wire_orpc_extent = NULL;
1812 if (msg->BufferLength < FIELD_OFFSET(WIRE_ORPCTHAT, extensions) + sizeof(DWORD))
1814 ERR("invalid buffer length\n");
1815 return RPC_E_INVALID_HEADER;
1818 memcpy(orpcthat, msg->Buffer, FIELD_OFFSET(WIRE_ORPCTHAT, extensions));
1819 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPCTHAT, extensions);
1821 if ((const char *)msg->Buffer + sizeof(DWORD) > end)
1822 return RPC_E_INVALID_HEADER;
1824 if (*(DWORD *)msg->Buffer)
1825 orpcthat->extensions = orpc_ext_array;
1826 else
1827 orpcthat->extensions = NULL;
1829 msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
1831 if (orpcthat->extensions)
1833 HRESULT hr = unmarshal_ORPC_EXTENT_ARRAY(msg, end, orpc_ext_array,
1834 first_wire_orpc_extent);
1835 if (FAILED(hr))
1836 return hr;
1839 if (orpcthat->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4))
1841 ERR("invalid flags %#lx\n", orpcthat->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4));
1842 return RPC_E_INVALID_HEADER;
1845 return S_OK;
1848 void rpc_execute_call(struct dispatch_params *params)
1850 struct message_state *message_state = NULL;
1851 RPC_MESSAGE *msg = (RPC_MESSAGE *)params->msg;
1852 char *original_buffer = msg->Buffer;
1853 ORPCTHIS orpcthis;
1854 ORPC_EXTENT_ARRAY orpc_ext_array;
1855 WIRE_ORPC_EXTENT *first_wire_orpc_extent;
1856 GUID old_causality_id;
1857 struct tlsdata *tlsdata;
1858 struct apartment *apt;
1860 if (FAILED(com_get_tlsdata(&tlsdata)))
1861 return;
1863 apt = com_get_current_apt();
1865 /* handle ORPCTHIS and server extensions */
1867 params->hr = unmarshal_ORPCTHIS(msg, &orpcthis, &orpc_ext_array, &first_wire_orpc_extent);
1868 if (params->hr != S_OK)
1870 msg->Buffer = original_buffer;
1871 goto exit;
1874 message_state = HeapAlloc(GetProcessHeap(), 0, sizeof(*message_state));
1875 if (!message_state)
1877 params->hr = E_OUTOFMEMORY;
1878 msg->Buffer = original_buffer;
1879 goto exit;
1882 message_state->prefix_data_len = (char *)msg->Buffer - original_buffer;
1883 message_state->binding_handle = msg->Handle;
1884 message_state->bypass_rpcrt = params->bypass_rpcrt;
1886 message_state->channel_hook_info.iid = params->iid;
1887 message_state->channel_hook_info.cbSize = sizeof(message_state->channel_hook_info);
1888 message_state->channel_hook_info.uCausality = orpcthis.cid;
1889 message_state->channel_hook_info.dwServerPid = GetCurrentProcessId();
1890 message_state->channel_hook_info.iMethod = msg->ProcNum;
1891 message_state->channel_hook_info.pObject = params->iface;
1893 if (orpcthis.extensions && first_wire_orpc_extent &&
1894 orpcthis.extensions->size)
1895 ChannelHooks_ServerNotify(&message_state->channel_hook_info, msg->DataRepresentation, first_wire_orpc_extent, orpcthis.extensions->size);
1897 msg->Handle = message_state;
1898 msg->BufferLength -= message_state->prefix_data_len;
1900 /* call message filter */
1902 if (apt->filter)
1904 DWORD handlecall;
1905 INTERFACEINFO interface_info;
1906 CALLTYPE calltype;
1908 interface_info.pUnk = params->iface;
1909 interface_info.iid = params->iid;
1910 interface_info.wMethod = msg->ProcNum;
1912 if (IsEqualGUID(&orpcthis.cid, &tlsdata->causality_id))
1913 calltype = CALLTYPE_NESTED;
1914 else if (tlsdata->pending_call_count_server == 0)
1915 calltype = CALLTYPE_TOPLEVEL;
1916 else
1917 calltype = CALLTYPE_TOPLEVEL_CALLPENDING;
1919 handlecall = IMessageFilter_HandleInComingCall(apt->filter,
1920 calltype,
1921 UlongToHandle(GetCurrentProcessId()),
1922 0 /* FIXME */,
1923 &interface_info);
1924 TRACE("IMessageFilter_HandleInComingCall returned %ld\n", handlecall);
1925 switch (handlecall)
1927 case SERVERCALL_REJECTED:
1928 params->hr = RPC_E_CALL_REJECTED;
1929 goto exit_reset_state;
1930 case SERVERCALL_RETRYLATER:
1931 #if 0 /* FIXME: handle retries on the client side before enabling this code */
1932 params->hr = RPC_E_RETRY;
1933 goto exit_reset_state;
1934 #else
1935 FIXME("retry call later not implemented\n");
1936 break;
1937 #endif
1938 case SERVERCALL_ISHANDLED:
1939 default:
1940 break;
1944 /* invoke the method */
1946 /* save the old causality ID - note: any calls executed while processing
1947 * messages received during the SendReceive will appear to originate from
1948 * this call - this should be checked with what Windows does */
1949 old_causality_id = tlsdata->causality_id;
1950 tlsdata->causality_id = orpcthis.cid;
1951 tlsdata->pending_call_count_server++;
1952 params->hr = IRpcStubBuffer_Invoke(params->stub, params->msg, params->chan);
1953 tlsdata->pending_call_count_server--;
1954 tlsdata->causality_id = old_causality_id;
1956 /* the invoke allocated a new buffer, so free the old one */
1957 if (message_state->bypass_rpcrt && original_buffer != msg->Buffer)
1958 HeapFree(GetProcessHeap(), 0, original_buffer);
1960 exit_reset_state:
1961 message_state = msg->Handle;
1962 msg->Handle = message_state->binding_handle;
1963 msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
1964 msg->BufferLength += message_state->prefix_data_len;
1966 exit:
1967 HeapFree(GetProcessHeap(), 0, message_state);
1968 if (params->handle) SetEvent(params->handle);
1971 static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg)
1973 struct dispatch_params *params;
1974 struct stub_manager *stub_manager;
1975 struct apartment *apt;
1976 IPID ipid;
1977 HRESULT hr;
1979 RpcBindingInqObject(msg->Handle, &ipid);
1981 TRACE("ipid = %s, iMethod = %d\n", debugstr_guid(&ipid), msg->ProcNum);
1983 params = HeapAlloc(GetProcessHeap(), 0, sizeof(*params));
1984 if (!params)
1986 RpcRaiseException(E_OUTOFMEMORY);
1987 return;
1990 hr = ipid_get_dispatch_params(&ipid, &apt, &stub_manager, &params->stub, &params->chan,
1991 &params->iid, &params->iface);
1992 if (hr != S_OK)
1994 ERR("no apartment found for ipid %s\n", debugstr_guid(&ipid));
1995 HeapFree(GetProcessHeap(), 0, params);
1996 RpcRaiseException(hr);
1997 return;
2000 params->msg = (RPCOLEMESSAGE *)msg;
2001 params->status = RPC_S_OK;
2002 params->hr = S_OK;
2003 params->handle = NULL;
2004 params->bypass_rpcrt = FALSE;
2006 /* Note: this is the important difference between STAs and MTAs - we
2007 * always execute RPCs to STAs in the thread that originally created the
2008 * apartment (i.e. the one that pumps messages to the window) */
2009 if (!apt->multi_threaded)
2011 params->handle = CreateEventW(NULL, FALSE, FALSE, NULL);
2013 TRACE("Calling apartment thread %#lx...\n", apt->tid);
2015 if (PostMessageW(apartment_getwindow(apt), DM_EXECUTERPC, 0, (LPARAM)params))
2016 WaitForSingleObject(params->handle, INFINITE);
2017 else
2019 ERR("PostMessage failed with error %lu\n", GetLastError());
2020 IRpcChannelBuffer_Release(params->chan);
2021 IRpcStubBuffer_Release(params->stub);
2023 CloseHandle(params->handle);
2025 else
2027 BOOL joined = FALSE;
2028 struct tlsdata *tlsdata;
2030 com_get_tlsdata(&tlsdata);
2032 if (!tlsdata->apt)
2034 enter_apartment(tlsdata, COINIT_MULTITHREADED);
2035 joined = TRUE;
2037 rpc_execute_call(params);
2038 if (joined)
2040 leave_apartment(tlsdata);
2044 hr = params->hr;
2045 if (params->chan)
2046 IRpcChannelBuffer_Release(params->chan);
2047 if (params->stub)
2048 IRpcStubBuffer_Release(params->stub);
2049 HeapFree(GetProcessHeap(), 0, params);
2051 stub_manager_int_release(stub_manager);
2052 apartment_release(apt);
2054 /* if IRpcStubBuffer_Invoke fails, we should raise an exception to tell
2055 * the RPC runtime that the call failed */
2056 if (hr != S_OK) RpcRaiseException(hr);
2059 /* stub registration */
2060 HRESULT rpc_register_interface(REFIID riid)
2062 struct registered_if *rif;
2063 BOOL found = FALSE;
2064 HRESULT hr = S_OK;
2066 TRACE("(%s)\n", debugstr_guid(riid));
2068 EnterCriticalSection(&csRegIf);
2069 LIST_FOR_EACH_ENTRY(rif, &registered_interfaces, struct registered_if, entry)
2071 if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid))
2073 rif->refs++;
2074 found = TRUE;
2075 break;
2078 if (!found)
2080 TRACE("Creating new interface\n");
2082 rif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rif));
2083 if (rif)
2085 RPC_STATUS status;
2087 rif->refs = 1;
2088 rif->If.Length = sizeof(RPC_SERVER_INTERFACE);
2089 /* RPC interface ID = COM interface ID */
2090 rif->If.InterfaceId.SyntaxGUID = *riid;
2091 rif->If.DispatchTable = &rpc_dispatch;
2092 /* all other fields are 0, including the version asCOM objects
2093 * always have a version of 0.0 */
2094 status = RpcServerRegisterIfEx(
2095 (RPC_IF_HANDLE)&rif->If,
2096 NULL, NULL,
2097 RPC_IF_OLE | RPC_IF_AUTOLISTEN,
2098 RPC_C_LISTEN_MAX_CALLS_DEFAULT,
2099 NULL);
2100 if (status == RPC_S_OK)
2101 list_add_tail(&registered_interfaces, &rif->entry);
2102 else
2104 ERR("RpcServerRegisterIfEx failed with error %ld\n", status);
2105 HeapFree(GetProcessHeap(), 0, rif);
2106 hr = HRESULT_FROM_WIN32(status);
2109 else
2110 hr = E_OUTOFMEMORY;
2112 LeaveCriticalSection(&csRegIf);
2113 return hr;
2116 /* stub unregistration */
2117 void rpc_unregister_interface(REFIID riid, BOOL wait)
2119 struct registered_if *rif;
2120 EnterCriticalSection(&csRegIf);
2121 LIST_FOR_EACH_ENTRY(rif, &registered_interfaces, struct registered_if, entry)
2123 if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid))
2125 if (!--rif->refs)
2127 RpcServerUnregisterIf((RPC_IF_HANDLE)&rif->If, NULL, wait);
2128 list_remove(&rif->entry);
2129 HeapFree(GetProcessHeap(), 0, rif);
2131 break;
2134 LeaveCriticalSection(&csRegIf);
2137 /* get the info for an OXID, including the IPID for the rem unknown interface
2138 * and the string binding */
2139 HRESULT rpc_resolve_oxid(OXID oxid, OXID_INFO *oxid_info)
2141 TRACE("%s\n", wine_dbgstr_longlong(oxid));
2143 oxid_info->dwTid = 0;
2144 oxid_info->dwPid = 0;
2145 oxid_info->dwAuthnHint = RPC_C_AUTHN_LEVEL_NONE;
2146 /* FIXME: this is a hack around not having an OXID resolver yet -
2147 * this function should contact the machine's OXID resolver and then it
2148 * should give us the IPID of the IRemUnknown interface */
2149 oxid_info->ipidRemUnknown.Data1 = 0xffffffff;
2150 oxid_info->ipidRemUnknown.Data2 = 0xffff;
2151 oxid_info->ipidRemUnknown.Data3 = 0xffff;
2152 memcpy(oxid_info->ipidRemUnknown.Data4, &oxid, sizeof(OXID));
2153 oxid_info->psa = NULL /* FIXME */;
2155 return S_OK;
2158 /* make the apartment reachable by other threads and processes and create the
2159 * IRemUnknown object */
2160 void rpc_start_remoting(struct apartment *apt)
2162 if (!InterlockedExchange(&apt->remoting_started, TRUE))
2164 WCHAR endpoint[200];
2165 RPC_STATUS status;
2167 get_rpc_endpoint(endpoint, &apt->oxid);
2169 status = RpcServerUseProtseqEpW(
2170 rpctransportW,
2171 RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
2172 endpoint,
2173 NULL);
2174 if (status != RPC_S_OK)
2175 ERR("Couldn't register endpoint %s\n", debugstr_w(endpoint));
2177 /* FIXME: move remote unknown exporting into this function */
2179 start_apartment_remote_unknown(apt);
2182 /******************************************************************************
2183 * DllDebugObjectRPCHook (combase.@)
2185 BOOL WINAPI DllDebugObjectRPCHook(BOOL trace, /* ORPC_INIT_ARGS * */ void *args)
2187 FIXME("%d, %p: stub\n", trace, args);
2189 return TRUE;
2192 /******************************************************************************
2193 * CoDecodeProxy (combase.@)
2195 HRESULT WINAPI CoDecodeProxy(DWORD client_pid, UINT64 proxy_addr, ServerInformation *server_info)
2197 FIXME("%lx, %s, %p.\n", client_pid, wine_dbgstr_longlong(proxy_addr), server_info);
2198 return E_NOTIMPL;