[OLE32] Sync with Wine Staging 4.0. CORE-15682
[reactos.git] / dll / win32 / ole32 / rpc.c
index 9b57206..bd4611d 100644 (file)
@@ -28,7 +28,6 @@
 
 #define COBJMACROS
 #define NONAMELESSUNION
-#define NONAMELESSSTRUCT
 
 #include "windef.h"
 #include "winbase.h"
@@ -39,6 +38,7 @@
 #include "rpc.h"
 #include "winerror.h"
 #include "winreg.h"
+#include "servprov.h"
 #include "wine/unicode.h"
 
 #include "compobj_private.h"
@@ -109,6 +109,7 @@ typedef struct
     OXID                   oxid; /* apartment in which the channel is valid */
     DWORD                  server_pid; /* id of server process */
     HANDLE                 event; /* cached event handle */
+    IID                    iid; /* IID of the proxy this belongs to */
 } ClientRpcChannelBuffer;
 
 struct dispatch_params
@@ -650,7 +651,7 @@ static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface,
 
     cif->Length = sizeof(RPC_CLIENT_INTERFACE);
     /* RPC interface ID = COM interface ID */
-    cif->InterfaceId.SyntaxGUID = *riid;
+    cif->InterfaceId.SyntaxGUID = This->iid;
     /* COM objects always have a version of 0.0 */
     cif->InterfaceId.SyntaxVersion.MajorVersion = 0;
     cif->InterfaceId.SyntaxVersion.MinorVersion = 0;
@@ -664,7 +665,7 @@ static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface,
     message_state->channel_hook_info.cbSize = sizeof(message_state->channel_hook_info);
     message_state->channel_hook_info.uCausality = COM_CurrentCausalityId();
     message_state->channel_hook_info.dwServerPid = This->server_pid;
-    message_state->channel_hook_info.iMethod = msg->ProcNum;
+    message_state->channel_hook_info.iMethod = msg->ProcNum & ~RPC_FLAGS_VALID_BIT;
     message_state->channel_hook_info.pObject = NULL; /* only present on server-side */
     message_state->target_hwnd = NULL;
     message_state->target_tid = 0;
@@ -682,7 +683,7 @@ static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface,
     }
 
     RpcBindingInqObject(message_state->binding_handle, &ipid);
-    hr = ipid_get_dispatch_params(&ipid, &apt, &message_state->params.stub,
+    hr = ipid_get_dispatch_params(&ipid, &apt, NULL, &message_state->params.stub,
                                   &message_state->params.chan,
                                   &message_state->params.iid,
                                   &message_state->params.iface);
@@ -830,14 +831,16 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac
     ORPC_EXTENT_ARRAY orpc_ext_array;
     WIRE_ORPC_EXTENT *first_wire_orpc_extent = NULL;
     HRESULT hrFault = S_OK;
+    APARTMENT *apt = apartment_get_current_or_mta();
 
     TRACE("(%p) iMethod=%d\n", olemsg, olemsg->iMethod);
 
-    hr = ClientRpcChannelBuffer_IsCorrectApartment(This, COM_CurrentApt());
+    hr = ClientRpcChannelBuffer_IsCorrectApartment(This, apt);
     if (hr != S_OK)
     {
         ERR("called from wrong apartment, should have been 0x%s\n",
             wine_dbgstr_longlong(This->oxid));
+        if (apt) apartment_release(apt);
         return RPC_E_WRONG_THREAD;
     }
     /* This situation should be impossible in multi-threaded apartments,
@@ -845,11 +848,12 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac
      * Note: doing a COM call during the processing of a sent message is
      * only disallowed if a client call is already being waited for
      * completion */
-    if (!COM_CurrentApt()->multi_threaded &&
+    if (!apt->multi_threaded &&
         COM_CurrentInfo()->pending_call_count_client &&
         InSendMessage())
     {
         ERR("can't make an outgoing COM call in response to a sent message\n");
+        apartment_release(apt);
         return RPC_E_CANTCALLOUT_ININPUTSYNCCALL;
     }
 
@@ -967,6 +971,7 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac
 
     TRACE("-- 0x%08x\n", hr);
 
+    apartment_release(apt);
     return hr;
 }
 
@@ -1092,9 +1097,9 @@ static const IRpcChannelBufferVtbl ServerRpcChannelBufferVtbl =
 
 /* returns a channel buffer for proxies */
 HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid,
-                                const OXID_INFO *oxid_info,
+                                const OXID_INFO *oxid_info, const IID *iid,
                                 DWORD dest_context, void *dest_context_data,
-                                IRpcChannelBuffer **chan)
+                                IRpcChannelBuffer **chan, APARTMENT *apt)
 {
     ClientRpcChannelBuffer *This;
     WCHAR                   endpoint[200];
@@ -1148,9 +1153,10 @@ HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid,
     This->super.dest_context = dest_context;
     This->super.dest_context_data = dest_context_data;
     This->bind = bind;
-    apartment_getoxid(COM_CurrentApt(), &This->oxid);
+    apartment_getoxid(apt, &This->oxid);
     This->server_pid = oxid_info->dwPid;
     This->event = NULL;
+    This->iid = *iid;
 
     *chan = &This->super.IRpcChannelBuffer_iface;
 
@@ -1441,6 +1447,7 @@ exit:
 static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg)
 {
     struct dispatch_params *params;
+    struct stub_manager *stub_manager;
     APARTMENT *apt;
     IPID ipid;
     HRESULT hr;
@@ -1456,7 +1463,7 @@ static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg)
         return;
     }
 
-    hr = ipid_get_dispatch_params(&ipid, &apt, &params->stub, &params->chan,
+    hr = ipid_get_dispatch_params(&ipid, &apt, &stub_manager, &params->stub, &params->chan,
                                   &params->iid, &params->iface);
     if (hr != S_OK)
     {
@@ -1494,16 +1501,17 @@ static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg)
     else
     {
         BOOL joined = FALSE;
-        if (!COM_CurrentInfo()->apt)
+        struct oletls *info = COM_CurrentInfo();
+
+        if (!info->apt)
         {
-            apartment_joinmta();
+            enter_apartment(info, COINIT_MULTITHREADED);
             joined = TRUE;
         }
         RPC_ExecuteCall(params);
         if (joined)
         {
-            apartment_release(COM_CurrentInfo()->apt);
-            COM_CurrentInfo()->apt = NULL;
+            leave_apartment(info);
         }
     }
 
@@ -1514,11 +1522,12 @@ static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg)
         IRpcStubBuffer_Release(params->stub);
     HeapFree(GetProcessHeap(), 0, params);
 
+    stub_manager_int_release(stub_manager);
     apartment_release(apt);
 
     /* if IRpcStubBuffer_Invoke fails, we should raise an exception to tell
      * the RPC runtime that the call failed */
-    if (hr) RpcRaiseException(hr);
+    if (hr != S_OK) RpcRaiseException(hr);
 }
 
 /* stub registration */
@@ -1579,7 +1588,7 @@ HRESULT RPC_RegisterInterface(REFIID riid)
 }
 
 /* stub unregistration */
-void RPC_UnregisterInterface(REFIID riid)
+void RPC_UnregisterInterface(REFIID riid, BOOL wait)
 {
     struct registered_if *rif;
     EnterCriticalSection(&csRegIf);
@@ -1589,7 +1598,7 @@ void RPC_UnregisterInterface(REFIID riid)
         {
             if (!--rif->refs)
             {
-                RpcServerUnregisterIf((RPC_IF_HANDLE)&rif->If, NULL, TRUE);
+                RpcServerUnregisterIf((RPC_IF_HANDLE)&rif->If, NULL, wait);
                 list_remove(&rif->entry);
                 HeapFree(GetProcessHeap(), 0, rif);
             }
@@ -1641,7 +1650,7 @@ void RPC_StartRemoting(struct apartment *apt)
 
         /* FIXME: move remote unknown exporting into this function */
     }
-    start_apartment_remote_unknown();
+    start_apartment_remote_unknown(apt);
 }
 
 
@@ -1651,10 +1660,11 @@ static HRESULT create_server(REFCLSID rclsid, HANDLE *process)
     static const WCHAR  embedding[] = { ' ', '-','E','m','b','e','d','d','i','n','g',0 };
     HKEY                key;
     HRESULT             hres;
-    WCHAR               command[MAX_PATH+sizeof(embedding)/sizeof(WCHAR)];
+    WCHAR               command[MAX_PATH+ARRAY_SIZE(embedding)];
     DWORD               size = (MAX_PATH+1) * sizeof(WCHAR);
     STARTUPINFOW        sinfo;
     PROCESS_INFORMATION pinfo;
+    LONG ret;
 
     hres = COM_OpenKeyForCLSID(rclsid, wszLocalServer32, KEY_READ, &key);
     if (FAILED(hres)) {
@@ -1662,9 +1672,9 @@ static HRESULT create_server(REFCLSID rclsid, HANDLE *process)
         return hres;
     }
 
-    hres = RegQueryValueExW(key, NULL, NULL, NULL, (LPBYTE)command, &size);
+    ret = RegQueryValueExW(key, NULL, NULL, NULL, (LPBYTE)command, &size);
     RegCloseKey(key);
-    if (hres) {
+    if (ret) {
         WARN("No default value for LocalServer32 key\n");
         return REGDB_E_CLASSNOTREG; /* FIXME: check retval */
     }
@@ -1680,7 +1690,7 @@ static HRESULT create_server(REFCLSID rclsid, HANDLE *process)
 
     /* FIXME: Win2003 supports a ServerExecutable value that is passed into
      * CreateProcess */
-    if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo)) {
+    if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &sinfo, &pinfo)) {
         WARN("failed to run local server %s\n", debugstr_w(command));
         return HRESULT_FROM_WIN32(GetLastError());
     }
@@ -1791,7 +1801,7 @@ static void get_localserver_pipe_name(WCHAR *pipefn, REFCLSID rclsid)
 {
     static const WCHAR wszPipeRef[] = {'\\','\\','.','\\','p','i','p','e','\\',0};
     strcpyW(pipefn, wszPipeRef);
-    StringFromGUID2(rclsid, pipefn + sizeof(wszPipeRef)/sizeof(wszPipeRef[0]) - 1, CHARS_IN_GUID);
+    StringFromGUID2(rclsid, pipefn + ARRAY_SIZE(wszPipeRef) - 1, CHARS_IN_GUID);
 }
 
 /* FIXME: should call to rpcss instead */
@@ -1806,6 +1816,7 @@ HRESULT RPC_GetLocalClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
     LARGE_INTEGER  seekto;
     ULARGE_INTEGER newpos;
     int            tries = 0;
+    IServiceProvider *local_server;
 
     static const int MAXTRIES = 30; /* 30 seconds */
 
@@ -1847,6 +1858,7 @@ HRESULT RPC_GetLocalClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
         bufferlen = 0;
         if (!ReadFile(hPipe,marshalbuffer,sizeof(marshalbuffer),&bufferlen,NULL)) {
             FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid));
+            CloseHandle(hPipe);
             Sleep(1000);
             continue;
         }
@@ -1859,14 +1871,17 @@ HRESULT RPC_GetLocalClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
         return E_NOINTERFACE;
     
     hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
-    if (hres) return hres;
+    if (hres != S_OK) return hres;
     hres = IStream_Write(pStm,marshalbuffer,bufferlen,&res);
-    if (hres) goto out;
+    if (hres != S_OK) goto out;
     seekto.u.LowPart = 0;seekto.u.HighPart = 0;
     hres = IStream_Seek(pStm,seekto,STREAM_SEEK_SET,&newpos);
     
-    TRACE("unmarshalling classfactory\n");
-    hres = CoUnmarshalInterface(pStm,&IID_IClassFactory,ppv);
+    TRACE("unmarshalling local server\n");
+    hres = CoUnmarshalInterface(pStm, &IID_IServiceProvider, (void**)&local_server);
+    if(SUCCEEDED(hres))
+        hres = IServiceProvider_QueryService(local_server, rclsid, iid, ppv);
+    IServiceProvider_Release(local_server);
 out:
     IStream_Release(pStm);
     return hres;
@@ -1877,7 +1892,7 @@ struct local_server_params
 {
     CLSID clsid;
     IStream *stream;
-    HANDLE ready_event;
+    HANDLE pipe;
     HANDLE stop_event;
     HANDLE thread;
     BOOL multi_use;
@@ -1898,7 +1913,7 @@ static DWORD WINAPI local_server_thread(LPVOID param)
     ULONG              res;
     BOOL multi_use = lsp->multi_use;
     OVERLAPPED ovl;
-    HANDLE pipe_event, hPipe, new_pipe;
+    HANDLE pipe_event, hPipe = lsp->pipe, new_pipe;
     DWORD  bytes;
 
     TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid));
@@ -1907,18 +1922,6 @@ static DWORD WINAPI local_server_thread(LPVOID param)
     get_localserver_pipe_name(pipefn, &lsp->clsid);
     ovl.hEvent = pipe_event = CreateEventW(NULL, FALSE, FALSE, NULL);
 
-    hPipe = CreateNamedPipeW( pipefn, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
-                              PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
-                              4096, 4096, 500 /* 0.5 second timeout */, NULL );
-    if (hPipe == INVALID_HANDLE_VALUE)
-    {
-        FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError());
-        CloseHandle(pipe_event);
-        return 1;
-    }
-
-    SetEvent(lsp->ready_event);
-
     while (1) {
         if (!ConnectNamedPipe(hPipe, &ovl))
         {
@@ -1929,50 +1932,38 @@ static DWORD WINAPI local_server_thread(LPVOID param)
                 DWORD ret;
                 ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
                 if (ret != WAIT_OBJECT_0)
-                {
-                    CloseHandle(hPipe);
                     break;
-                }
             }
             /* client already connected isn't an error */
             else if (error != ERROR_PIPE_CONNECTED)
             {
                 ERR("ConnectNamedPipe failed with error %d\n", GetLastError());
-                CloseHandle(hPipe);
                 break;
             }
         }
 
-        TRACE("marshalling IClassFactory to client\n");
+        TRACE("marshalling LocalServer to client\n");
         
         hres = IStream_Stat(pStm,&ststg,STATFLAG_NONAME);
-        if (hres)
-        {
-            CloseHandle(hPipe);
-            CloseHandle(pipe_event);
-            return hres;
-        }
+        if (hres != S_OK)
+            break;
 
         seekto.u.LowPart = 0;
         seekto.u.HighPart = 0;
         hres = IStream_Seek(pStm,seekto,STREAM_SEEK_SET,&newpos);
-        if (hres) {
+        if (hres != S_OK) {
             FIXME("IStream_Seek failed, %x\n",hres);
-            CloseHandle(hPipe);
-            CloseHandle(pipe_event);
-            return hres;
+            break;
         }
 
         buflen = ststg.cbSize.u.LowPart;
         buffer = HeapAlloc(GetProcessHeap(),0,buflen);
         
         hres = IStream_Read(pStm,buffer,buflen,&res);
-        if (hres) {
+        if (hres != S_OK) {
             FIXME("Stream Read failed, %x\n",hres);
-            CloseHandle(hPipe);
-            CloseHandle(pipe_event);
             HeapFree(GetProcessHeap(),0,buffer);
-            return hres;
+            break;
         }
         
         WriteFile(hPipe,buffer,buflen,&res,&ovl);
@@ -1981,35 +1972,36 @@ static DWORD WINAPI local_server_thread(LPVOID param)
 
         FlushFileBuffers(hPipe);
         DisconnectNamedPipe(hPipe);
-        TRACE("done marshalling IClassFactory\n");
+        TRACE("done marshalling LocalServer\n");
 
         if (!multi_use)
         {
             TRACE("single use object, shutting down pipe %s\n", debugstr_w(pipefn));
-            CloseHandle(hPipe);
             break;
         }
         new_pipe = CreateNamedPipeW( pipefn, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
                                      PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
                                      4096, 4096, 500 /* 0.5 second timeout */, NULL );
-        CloseHandle(hPipe);
         if (new_pipe == INVALID_HANDLE_VALUE)
         {
             FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError());
-            CloseHandle(pipe_event);
-            return 1;
+            break;
         }
+        CloseHandle(hPipe);
         hPipe = new_pipe;
     }
+
     CloseHandle(pipe_event);
+    CloseHandle(hPipe);
     return 0;
 }
 
 /* starts listening for a local server */
 HRESULT RPC_StartLocalServer(REFCLSID clsid, IStream *stream, BOOL multi_use, void **registration)
 {
-    DWORD tid;
+    DWORD tid, err;
     struct local_server_params *lsp;
+    WCHAR pipefn[100];
 
     lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp));
     if (!lsp)
@@ -2018,34 +2010,36 @@ HRESULT RPC_StartLocalServer(REFCLSID clsid, IStream *stream, BOOL multi_use, vo
     lsp->clsid = *clsid;
     lsp->stream = stream;
     IStream_AddRef(stream);
-    lsp->ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
-    if (!lsp->ready_event)
-    {
-        HeapFree(GetProcessHeap(), 0, lsp);
-        return HRESULT_FROM_WIN32(GetLastError());
-    }
     lsp->stop_event = CreateEventW(NULL, FALSE, FALSE, NULL);
     if (!lsp->stop_event)
     {
-        CloseHandle(lsp->ready_event);
         HeapFree(GetProcessHeap(), 0, lsp);
         return HRESULT_FROM_WIN32(GetLastError());
     }
     lsp->multi_use = multi_use;
 
+    get_localserver_pipe_name(pipefn, &lsp->clsid);
+    lsp->pipe = CreateNamedPipeW(pipefn, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+                                 PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
+                                 4096, 4096, 500 /* 0.5 second timeout */, NULL);
+    if (lsp->pipe == INVALID_HANDLE_VALUE)
+    {
+        err = GetLastError();
+        FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError());
+        CloseHandle(lsp->stop_event);
+        HeapFree(GetProcessHeap(), 0, lsp);
+        return HRESULT_FROM_WIN32(err);
+    }
+
     lsp->thread = CreateThread(NULL, 0, local_server_thread, lsp, 0, &tid);
     if (!lsp->thread)
     {
-        CloseHandle(lsp->ready_event);
+        CloseHandle(lsp->pipe);
         CloseHandle(lsp->stop_event);
         HeapFree(GetProcessHeap(), 0, lsp);
         return HRESULT_FROM_WIN32(GetLastError());
     }
 
-    WaitForSingleObject(lsp->ready_event, INFINITE);
-    CloseHandle(lsp->ready_event);
-    lsp->ready_event = NULL;
-
     *registration = lsp;
     return S_OK;
 }