Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/combase/apartment.c | 10 +- dlls/combase/combase.c | 274 ++++++++++++++++++++++++- dlls/combase/combase.spec | 9 +- dlls/combase/combase_private.h | 9 +- dlls/combase/rpc.c | 170 ++++++++++++++++ dlls/ole32/compobj.c | 361 --------------------------------- dlls/ole32/compobj_private.h | 8 - dlls/ole32/ole32.spec | 10 +- dlls/ole32/rpc.c | 179 ---------------- 9 files changed, 457 insertions(+), 573 deletions(-)
diff --git a/dlls/combase/apartment.c b/dlls/combase/apartment.c index 3df8b165c13..356935ae26b 100644 --- a/dlls/combase/apartment.c +++ b/dlls/combase/apartment.c @@ -285,9 +285,6 @@ static ULONG WINAPI local_server_Release(IServiceProvider *iface) return refcount; }
-extern HRESULT WINAPI InternalGetRegisteredClassObject(struct apartment *apt, REFGUID guid, - DWORD clscontext, IUnknown **obj); - static HRESULT WINAPI local_server_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **obj) { struct local_server *local_server = impl_from_IServiceProvider(iface); @@ -300,7 +297,7 @@ static HRESULT WINAPI local_server_QueryService(IServiceProvider *iface, REFGUID if (!local_server->apt) return E_UNEXPECTED;
- if (SUCCEEDED(InternalGetRegisteredClassObject(apt, guid, CLSCTX_LOCAL_SERVER, &unk))) + if ((unk = com_get_registered_class_object(apt, guid, CLSCTX_LOCAL_SERVER))) { hr = IUnknown_QueryInterface(unk, riid, obj); IUnknown_Release(unk); @@ -317,7 +314,7 @@ static const IServiceProviderVtbl local_server_vtbl = local_server_QueryService };
-HRESULT WINAPI apartment_get_local_server_stream(struct apartment *apt, IStream **ret) +HRESULT apartment_get_local_server_stream(struct apartment *apt, IStream **ret) { HRESULT hr = S_OK;
@@ -446,7 +443,6 @@ void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay) LeaveCriticalSection(&apt->cs); }
-extern void WINAPI InternalRevokeAllClasses(struct apartment *apt); extern HRESULT WINAPI Internal_apartment_disconnectproxies(struct apartment *apt); extern ULONG WINAPI Internal_stub_manager_int_release(struct stub_manager *stubmgr);
@@ -499,7 +495,7 @@ void WINAPI apartment_release(struct apartment *apt) }
/* Release the references to the registered class objects */ - InternalRevokeAllClasses(apt); + apartment_revoke_all_classes(apt);
/* no locking is needed for this apartment, because no other thread * can access it at this point */ diff --git a/dlls/combase/combase.c b/dlls/combase/combase.c index 28a63c6c7f4..6d058ea6fa5 100644 --- a/dlls/combase/combase.c +++ b/dlls/combase/combase.c @@ -47,6 +47,8 @@ extern HRESULT WINAPI Ole32DllGetClassObject(REFCLSID rclsid, REFIID riid, void */ static LONG com_lockcount;
+static LONG com_server_process_refcount; + struct comclassredirect_data { ULONG size; @@ -113,6 +115,57 @@ static CRITICAL_SECTION_DEBUG psclsid_cs_debug = }; static CRITICAL_SECTION cs_registered_ps = { &psclsid_cs_debug, -1, 0, 0, 0, 0 };
+/* + * TODO: Make this data structure aware of inter-process communication. This + * means that parts of this will be exported to rpcss. + */ +struct registered_class +{ + struct list entry; + CLSID clsid; + OXID apartment_id; + IUnknown *object; + DWORD clscontext; + DWORD flags; + DWORD cookie; + void *RpcRegistration; +}; + +static struct list registered_classes = LIST_INIT(registered_classes); + +static CRITICAL_SECTION registered_classes_cs; +static CRITICAL_SECTION_DEBUG registered_classes_cs_debug = +{ + 0, 0, ®istered_classes_cs, + { ®istered_classes_cs_debug.ProcessLocksList, ®istered_classes_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": registered_classes_cs") } +}; +static CRITICAL_SECTION registered_classes_cs = { ®istered_classes_cs_debug, -1, 0, 0, 0, 0 }; + +IUnknown * com_get_registered_class_object(const struct apartment *apt, REFCLSID rclsid, DWORD clscontext) +{ + struct registered_class *cur; + IUnknown *object = NULL; + + EnterCriticalSection(®istered_classes_cs); + + LIST_FOR_EACH_ENTRY(cur, ®istered_classes, struct registered_class, entry) + { + if ((apt->oxid == cur->apartment_id) && + (clscontext & cur->clscontext) && + IsEqualGUID(&cur->clsid, rclsid)) + { + object = cur->object; + IUnknown_AddRef(cur->object); + break; + } + } + + LeaveCriticalSection(®istered_classes_cs); + + return object; +} + static struct init_spy *get_spy_entry(struct tlsdata *tlsdata, unsigned int id) { struct init_spy *spy; @@ -1498,8 +1551,8 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(REFCLSID rclsid, DWORD clscont COSERVERINFO *server_info, REFIID riid, void **obj) { struct class_reg_data clsreg = { 0 }; - IUnknown *regClassObject; HRESULT hr = E_UNEXPECTED; + IUnknown *registered_obj; struct apartment *apt;
TRACE("%s, %s\n", debugstr_guid(rclsid), debugstr_guid(riid)); @@ -1558,10 +1611,10 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(REFCLSID rclsid, DWORD clscont * First, try and see if we can't match the class ID with one of the * registered classes. */ - if (InternalGetRegisteredClassObject(apt, rclsid, clscontext, ®ClassObject) == S_OK) + if ((registered_obj = com_get_registered_class_object(apt, rclsid, clscontext))) { - hr = IUnknown_QueryInterface(regClassObject, riid, obj); - IUnknown_Release(regClassObject); + hr = IUnknown_QueryInterface(registered_obj, riid, obj); + IUnknown_Release(registered_obj); apartment_release(apt); return hr; } @@ -2676,6 +2729,215 @@ HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier) return tlsdata->apt ? S_OK : CO_E_NOTINITIALIZED; }
+/****************************************************************************** + * CoRegisterClassObject (combase.@) + * BUGS + * MSDN claims that multiple interface registrations are legal, but we + * can't do that with our current implementation. + */ +HRESULT WINAPI CoRegisterClassObject(REFCLSID rclsid, IUnknown *object, DWORD clscontext, + DWORD flags, DWORD *cookie) +{ + static LONG next_cookie; + + struct registered_class *newclass; + IUnknown *found_object; + struct apartment *apt; + HRESULT hr = S_OK; + + TRACE("%s, %p, %#x, %#x, %p\n", debugstr_guid(rclsid), object, clscontext, flags, cookie); + + if (!cookie || !object) + return E_INVALIDARG; + + if (!(apt = apartment_get_current_or_mta())) + { + ERR("COM was not initialized\n"); + return CO_E_NOTINITIALIZED; + } + + *cookie = 0; + + /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what + * differentiates the flag from REGCLS_MULTI_SEPARATE. */ + if (flags & REGCLS_MULTIPLEUSE) + clscontext |= CLSCTX_INPROC_SERVER; + + /* + * First, check if the class is already registered. + * If it is, this should cause an error. + */ + if ((found_object = com_get_registered_class_object(apt, rclsid, clscontext))) + { + if (flags & REGCLS_MULTIPLEUSE) + { + if (clscontext & CLSCTX_LOCAL_SERVER) + hr = CoLockObjectExternal(found_object, TRUE, FALSE); + IUnknown_Release(found_object); + apartment_release(apt); + return hr; + } + + IUnknown_Release(found_object); + ERR("object already registered for class %s\n", debugstr_guid(rclsid)); + apartment_release(apt); + return CO_E_OBJISREG; + } + + newclass = heap_alloc(sizeof(*newclass)); + if (!newclass) + { + apartment_release(apt); + return E_OUTOFMEMORY; + } + + newclass->clsid = *rclsid; + newclass->apartment_id = apt->oxid; + newclass->clscontext = clscontext; + newclass->flags = flags; + newclass->RpcRegistration = NULL; + + if (!(newclass->cookie = InterlockedIncrement(&next_cookie))) + newclass->cookie = InterlockedIncrement(&next_cookie); + + newclass->object = object; + IUnknown_AddRef(newclass->object); + + EnterCriticalSection(®istered_classes_cs); + list_add_tail(®istered_classes, &newclass->entry); + LeaveCriticalSection(®istered_classes_cs); + + *cookie = newclass->cookie; + + if (clscontext & CLSCTX_LOCAL_SERVER) + { + IStream *marshal_stream; + + hr = apartment_get_local_server_stream(apt, &marshal_stream); + if(FAILED(hr)) + { + apartment_release(apt); + return hr; + } + + hr = rpc_start_local_server(&newclass->clsid, marshal_stream, flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE), + &newclass->RpcRegistration); + IStream_Release(marshal_stream); + } + + apartment_release(apt); + return S_OK; +} + +static void com_revoke_class_object(struct registered_class *entry) +{ + list_remove(&entry->entry); + + if (entry->clscontext & CLSCTX_LOCAL_SERVER) + rpc_stop_local_server(entry->RpcRegistration); + + IUnknown_Release(entry->object); + heap_free(entry); +} + +void apartment_revoke_all_classes(const struct apartment *apt) +{ + struct registered_class *cur, *cur2; + + EnterCriticalSection(®istered_classes_cs); + + LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, ®istered_classes, struct registered_class, entry) + { + if (cur->apartment_id == apt->oxid) + com_revoke_class_object(cur); + } + + LeaveCriticalSection(®istered_classes_cs); +} + +/*********************************************************************** + * CoRevokeClassObject (combase.@) + */ +HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject(DWORD cookie) +{ + HRESULT hr = E_INVALIDARG; + struct registered_class *cur; + struct apartment *apt; + + TRACE("%#x\n", cookie); + + if (!(apt = apartment_get_current_or_mta())) + { + ERR("COM was not initialized\n"); + return CO_E_NOTINITIALIZED; + } + + EnterCriticalSection(®istered_classes_cs); + + LIST_FOR_EACH_ENTRY(cur, ®istered_classes, struct registered_class, entry) + { + if (cur->cookie != cookie) + continue; + + if (cur->apartment_id == apt->oxid) + { + com_revoke_class_object(cur); + hr = S_OK; + } + else + { + ERR("called from wrong apartment, should be called from %s\n", wine_dbgstr_longlong(cur->apartment_id)); + hr = RPC_E_WRONG_THREAD; + } + + break; + } + + LeaveCriticalSection(®istered_classes_cs); + apartment_release(apt); + + return hr; +} + +/*********************************************************************** + * CoAddRefServerProcess (combase.@) + */ +ULONG WINAPI CoAddRefServerProcess(void) +{ + ULONG refs; + + TRACE("\n"); + + EnterCriticalSection(®istered_classes_cs); + refs = ++com_server_process_refcount; + LeaveCriticalSection(®istered_classes_cs); + + TRACE("refs before: %d\n", refs - 1); + + return refs; +} + +/*********************************************************************** + * CoReleaseServerProcess [OLE32.@] + */ +ULONG WINAPI CoReleaseServerProcess(void) +{ + ULONG refs; + + TRACE("\n"); + + EnterCriticalSection(®istered_classes_cs); + + refs = --com_server_process_refcount; + /* FIXME: suspend objects */ + + LeaveCriticalSection(®istered_classes_cs); + + TRACE("refs after: %d\n", refs); + + return refs; +} + /*********************************************************************** * DllMain (combase.@) */ @@ -2688,6 +2950,10 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved) case DLL_PROCESS_ATTACH: hProxyDll = hinstDLL; break; + case DLL_PROCESS_DETACH: + if (reserved) break; + DeleteCriticalSection(®istered_classes_cs); + break; }
return TRUE; diff --git a/dlls/combase/combase.spec b/dlls/combase/combase.spec index ea2177ca7ba..401979119b4 100644 --- a/dlls/combase/combase.spec +++ b/dlls/combase/combase.spec @@ -73,7 +73,7 @@ @ stub CleanupOleStateInAllTls @ stdcall CleanupTlsOleState(ptr) @ stub ClearCleanupFlag -@ stdcall CoAddRefServerProcess() ole32.CoAddRefServerProcess +@ stdcall CoAddRefServerProcess() @ stub CoAllowUnmarshalerCLSID @ stub CoCancelCall @ stdcall CoCopyProxy(ptr ptr) @@ -139,7 +139,7 @@ @ stdcall CoQueryProxyBlanket(ptr ptr ptr ptr ptr ptr ptr ptr) @ stub CoReactivateObject @ stub CoRegisterActivationFilter -@ stdcall CoRegisterClassObject(ptr ptr long long ptr) ole32.CoRegisterClassObject +@ stdcall CoRegisterClassObject(ptr ptr long long ptr) @ stdcall CoRegisterInitializeSpy(ptr ptr) @ stdcall CoRegisterMallocSpy(ptr) @ stdcall CoRegisterMessageFilter(ptr ptr) @@ -147,11 +147,11 @@ @ stdcall CoRegisterSurrogate(ptr) ole32.CoRegisterSurrogate @ stdcall CoRegisterSurrogateEx(ptr ptr) ole32.CoRegisterSurrogateEx @ stdcall CoReleaseMarshalData(ptr) ole32.CoReleaseMarshalData -@ stdcall CoReleaseServerProcess() ole32.CoReleaseServerProcess +@ stdcall CoReleaseServerProcess() @ stdcall CoResumeClassObjects() ole32.CoResumeClassObjects @ stub CoRetireServer @ stdcall CoRevertToSelf() -@ stdcall CoRevokeClassObject(long) ole32.CoRevokeClassObject +@ stdcall CoRevokeClassObject(long) @ stdcall CoRevokeInitializeSpy(int64) @ stdcall CoRevokeMallocSpy() @ stub CoSetCancelObject @@ -359,5 +359,4 @@ @ stdcall apartment_getwindow(ptr) @ stdcall apartment_global_cleanup() @ stdcall apartment_createwindowifneeded(ptr) -@ stdcall apartment_get_local_server_stream(ptr ptr) @ stdcall apartment_findfromtid(long) diff --git a/dlls/combase/combase_private.h b/dlls/combase/combase_private.h index c6d090707a7..61b76657494 100644 --- a/dlls/combase/combase_private.h +++ b/dlls/combase/combase_private.h @@ -54,9 +54,6 @@ struct apartment struct list usage_cookies; /* Used for refcount control with CoIncrementMTAUsage()/CoDecrementMTAUsage(). */ };
-extern HRESULT WINAPI InternalGetRegisteredClassObject(struct apartment *apt, REFGUID guid, - DWORD clscontext, IUnknown **obj); - HRESULT open_key_for_clsid(REFCLSID clsid, const WCHAR *keyname, REGSAM access, HKEY *subkey) DECLSPEC_HIDDEN; HRESULT open_appidkey_from_clsid(REFCLSID clsid, REGSAM access, HKEY *subkey) DECLSPEC_HIDDEN;
@@ -112,6 +109,8 @@ void apartment_freeunusedlibraries(struct apartment *apt, DWORD unload_delay) DE /* RpcSs interface */ HRESULT rpcss_get_next_seqid(DWORD *id) DECLSPEC_HIDDEN; HRESULT rpc_get_local_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN; +HRESULT rpc_start_local_server(REFCLSID clsid, IStream *stream, BOOL multi_use, void **registration) DECLSPEC_HIDDEN; +void rpc_stop_local_server(void *registration) DECLSPEC_HIDDEN;
/* stub managers hold refs on the object and each interface stub */ struct stub_manager @@ -171,6 +170,10 @@ void apartment_decrement_mta_usage(CO_MTA_USAGE_COOKIE cookie) DECLSPEC_HIDDEN; struct apartment * apartment_get_mta(void) DECLSPEC_HIDDEN; HRESULT apartment_get_inproc_class_object(struct apartment *apt, const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, BOOL hostifnecessary, void **ppv) DECLSPEC_HIDDEN; +HRESULT apartment_get_local_server_stream(struct apartment *apt, IStream **ret) DECLSPEC_HIDDEN; +IUnknown *com_get_registered_class_object(const struct apartment *apartment, REFCLSID rclsid, + DWORD clscontext) DECLSPEC_HIDDEN; +void apartment_revoke_all_classes(const struct apartment *apt) DECLSPEC_HIDDEN;
/* Stub Manager */
diff --git a/dlls/combase/rpc.c b/dlls/combase/rpc.c index 2b655da8bad..cb503e9ae7c 100644 --- a/dlls/combase/rpc.c +++ b/dlls/combase/rpc.c @@ -459,3 +459,173 @@ out: IStream_Release(pStm); return hr; } + +struct local_server_params +{ + CLSID clsid; + IStream *stream; + HANDLE pipe; + HANDLE stop_event; + HANDLE thread; + BOOL multi_use; +}; + +/* FIXME: should call to rpcss instead */ +static DWORD WINAPI local_server_thread(void *param) +{ + struct local_server_params * lsp = param; + WCHAR pipefn[100]; + HRESULT hres; + IStream *pStm = lsp->stream; + STATSTG ststg; + unsigned char *buffer; + int buflen; + LARGE_INTEGER seekto; + ULARGE_INTEGER newpos; + ULONG res; + BOOL multi_use = lsp->multi_use; + OVERLAPPED ovl; + HANDLE pipe_event, hPipe = lsp->pipe, new_pipe; + DWORD bytes; + + TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid)); + + memset(&ovl, 0, sizeof(ovl)); + get_localserver_pipe_name(pipefn, &lsp->clsid); + ovl.hEvent = pipe_event = CreateEventW(NULL, FALSE, FALSE, NULL); + + while (1) { + if (!ConnectNamedPipe(hPipe, &ovl)) + { + DWORD error = GetLastError(); + if (error == ERROR_IO_PENDING) + { + HANDLE handles[2] = { pipe_event, lsp->stop_event }; + DWORD ret; + ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE); + if (ret != WAIT_OBJECT_0) + break; + } + /* client already connected isn't an error */ + else if (error != ERROR_PIPE_CONNECTED) + { + ERR("ConnectNamedPipe failed with error %d\n", GetLastError()); + break; + } + } + + TRACE("marshalling LocalServer to client\n"); + + hres = IStream_Stat(pStm,&ststg,STATFLAG_NONAME); + if (hres != S_OK) + break; + + seekto.u.LowPart = 0; + seekto.u.HighPart = 0; + hres = IStream_Seek(pStm,seekto,STREAM_SEEK_SET,&newpos); + if (hres != S_OK) { + FIXME("IStream_Seek failed, %x\n",hres); + break; + } + + buflen = ststg.cbSize.u.LowPart; + buffer = HeapAlloc(GetProcessHeap(),0,buflen); + + hres = IStream_Read(pStm,buffer,buflen,&res); + if (hres != S_OK) { + FIXME("Stream Read failed, %x\n",hres); + HeapFree(GetProcessHeap(),0,buffer); + break; + } + + WriteFile(hPipe,buffer,buflen,&res,&ovl); + GetOverlappedResult(hPipe, &ovl, &bytes, TRUE); + HeapFree(GetProcessHeap(),0,buffer); + + FlushFileBuffers(hPipe); + DisconnectNamedPipe(hPipe); + TRACE("done marshalling LocalServer\n"); + + if (!multi_use) + { + TRACE("single use object, shutting down pipe %s\n", debugstr_w(pipefn)); + 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 ); + if (new_pipe == INVALID_HANDLE_VALUE) + { + FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError()); + break; + } + CloseHandle(hPipe); + hPipe = new_pipe; + } + + CloseHandle(pipe_event); + CloseHandle(hPipe); + return 0; +} + +HRESULT rpc_start_local_server(REFCLSID clsid, IStream *stream, BOOL multi_use, void **registration) +{ + DWORD tid, err; + struct local_server_params *lsp; + WCHAR pipefn[100]; + + lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp)); + if (!lsp) + return E_OUTOFMEMORY; + + lsp->clsid = *clsid; + lsp->stream = stream; + IStream_AddRef(stream); + lsp->stop_event = CreateEventW(NULL, FALSE, FALSE, NULL); + if (!lsp->stop_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->pipe); + CloseHandle(lsp->stop_event); + HeapFree(GetProcessHeap(), 0, lsp); + return HRESULT_FROM_WIN32(GetLastError()); + } + + *registration = lsp; + return S_OK; +} + +void rpc_stop_local_server(void *registration) +{ + struct local_server_params *lsp = registration; + + /* signal local_server_thread to stop */ + SetEvent(lsp->stop_event); + /* wait for it to exit */ + WaitForSingleObject(lsp->thread, INFINITE); + + IStream_Release(lsp->stream); + CloseHandle(lsp->stop_event); + CloseHandle(lsp->thread); + HeapFree(GetProcessHeap(), 0, lsp); +} diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index 18580e9b235..ef9888d9e38 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -142,40 +142,6 @@ struct class_reg_data } u; };
-/* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */ -static LONG s_COMServerProcessReferences = 0; - -/* - * This linked list contains the list of registered class objects. These - * are mostly used to register the factories for out-of-proc servers of OLE - * objects. - * - * TODO: Make this data structure aware of inter-process communication. This - * means that parts of this will be exported to rpcss. - */ -typedef struct tagRegisteredClass -{ - struct list entry; - CLSID classIdentifier; - OXID apartment_id; - LPUNKNOWN classObject; - DWORD runContext; - DWORD connectFlags; - DWORD dwCookie; - void *RpcRegistration; -} RegisteredClass; - -static struct list RegisteredClassList = LIST_INIT(RegisteredClassList); - -static CRITICAL_SECTION csRegisteredClassList; -static CRITICAL_SECTION_DEBUG class_cs_debug = -{ - 0, 0, &csRegisteredClassList, - { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") } -}; -static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 }; - static inline enum comclass_miscfields dvaspect_to_miscfields(DWORD aspect) { switch (aspect) @@ -374,32 +340,6 @@ LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *ret return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) ); }
-static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass) -{ - list_remove(&curClass->entry); - - if (curClass->runContext & CLSCTX_LOCAL_SERVER) - RPC_StopLocalServer(curClass->RpcRegistration); - - IUnknown_Release(curClass->classObject); - HeapFree(GetProcessHeap(), 0, curClass); -} - -void WINAPI InternalRevokeAllClasses(const struct apartment *apt) -{ - RegisteredClass *curClass, *cursor; - - EnterCriticalSection( &csRegisteredClassList ); - - LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry) - { - if (curClass->apartment_id == apt->oxid) - COM_RevokeRegisteredClassObject(curClass); - } - - LeaveCriticalSection( &csRegisteredClassList ); -} - /****************************************************************************** * Implementation of the manual reset event object. (CLSID_ManualResetEvent) */ @@ -549,69 +489,6 @@ HRESULT WINAPI ManualResetEvent_CreateInstance(IClassFactory *iface, IUnknown *o return hr; }
-/*********************************************************************** - * CoRevokeClassObject [OLE32.@] - * - * Removes a class object from the class registry. - * - * PARAMS - * dwRegister [I] Cookie returned from CoRegisterClassObject(). - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - * - * NOTES - * Must be called from the same apartment that called CoRegisterClassObject(), - * otherwise it will fail with RPC_E_WRONG_THREAD. - * - * SEE ALSO - * CoRegisterClassObject - */ -HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject( - DWORD dwRegister) -{ - HRESULT hr = E_INVALIDARG; - RegisteredClass *curClass; - struct apartment *apt; - - TRACE("(%08x)\n",dwRegister); - - if (!(apt = apartment_get_current_or_mta())) - { - ERR("COM was not initialized\n"); - return CO_E_NOTINITIALIZED; - } - - EnterCriticalSection( &csRegisteredClassList ); - - LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry) - { - /* - * Check if we have a match on the cookie. - */ - if (curClass->dwCookie == dwRegister) - { - if (curClass->apartment_id == apt->oxid) - { - COM_RevokeRegisteredClassObject(curClass); - hr = S_OK; - } - else - { - ERR("called from wrong apartment, should be called from %s\n", - wine_dbgstr_longlong(curClass->apartment_id)); - hr = RPC_E_WRONG_THREAD; - } - break; - } - } - - LeaveCriticalSection( &csRegisteredClassList ); - apartment_release(apt); - return hr; -} - static void COM_TlsDestroy(void) { struct oletls *info = NtCurrentTeb()->ReservedForOle; @@ -772,182 +649,6 @@ HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY return S_OK; }
-/*** - * This internal method is used to scan the registered class list to - * find a class object. - * - * Params: - * rclsid Class ID of the class to find. - * dwClsContext Class context to match. - * ppv [out] returns a pointer to the class object. Complying - * to normal COM usage, this method will increase the - * reference count on this object. - */ -HRESULT WINAPI InternalGetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid, - DWORD dwClsContext, LPUNKNOWN* ppUnk) -{ - HRESULT hr = S_FALSE; - RegisteredClass *curClass; - - EnterCriticalSection( &csRegisteredClassList ); - - LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry) - { - /* - * Check if we have a match on the class ID and context. - */ - if ((apt->oxid == curClass->apartment_id) && - (dwClsContext & curClass->runContext) && - IsEqualGUID(&(curClass->classIdentifier), rclsid)) - { - /* - * We have a match, return the pointer to the class object. - */ - *ppUnk = curClass->classObject; - - IUnknown_AddRef(curClass->classObject); - - hr = S_OK; - break; - } - } - - LeaveCriticalSection( &csRegisteredClassList ); - - return hr; -} - -/****************************************************************************** - * CoRegisterClassObject [OLE32.@] - * - * Registers the class object for a given class ID. Servers housed in EXE - * files use this method instead of exporting DllGetClassObject to allow - * other code to connect to their objects. - * - * PARAMS - * rclsid [I] CLSID of the object to register. - * pUnk [I] IUnknown of the object. - * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable. - * flags [I] REGCLS flags indicating how connections are made. - * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject. - * - * RETURNS - * S_OK on success, - * E_INVALIDARG if lpdwRegister or pUnk are NULL, - * CO_E_OBJISREG if the object is already registered. We should not return this. - * - * SEE ALSO - * CoRevokeClassObject, CoGetClassObject - * - * NOTES - * In-process objects are only registered for the current apartment. - * CoGetClassObject() and CoCreateInstance() will not return objects registered - * in other apartments. - * - * BUGS - * MSDN claims that multiple interface registrations are legal, but we - * can't do that with our current implementation. - */ -HRESULT WINAPI CoRegisterClassObject( - REFCLSID rclsid, - LPUNKNOWN pUnk, - DWORD dwClsContext, - DWORD flags, - LPDWORD lpdwRegister) -{ - static LONG next_cookie; - RegisteredClass* newClass; - LPUNKNOWN foundObject; - HRESULT hr; - struct apartment *apt; - - TRACE("(%s,%p,0x%08x,0x%08x,%p)\n", - debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister); - - if ( (lpdwRegister==0) || (pUnk==0) ) - return E_INVALIDARG; - - if (!(apt = apartment_get_current_or_mta())) - { - ERR("COM was not initialized\n"); - return CO_E_NOTINITIALIZED; - } - - *lpdwRegister = 0; - - /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what - * differentiates the flag from REGCLS_MULTI_SEPARATE. */ - if (flags & REGCLS_MULTIPLEUSE) - dwClsContext |= CLSCTX_INPROC_SERVER; - - /* - * First, check if the class is already registered. - * If it is, this should cause an error. - */ - hr = InternalGetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject); - if (hr == S_OK) { - if (flags & REGCLS_MULTIPLEUSE) { - if (dwClsContext & CLSCTX_LOCAL_SERVER) - hr = CoLockObjectExternal(foundObject, TRUE, FALSE); - IUnknown_Release(foundObject); - apartment_release(apt); - return hr; - } - IUnknown_Release(foundObject); - ERR("object already registered for class %s\n", debugstr_guid(rclsid)); - apartment_release(apt); - return CO_E_OBJISREG; - } - - newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass)); - if ( newClass == NULL ) - { - apartment_release(apt); - return E_OUTOFMEMORY; - } - - newClass->classIdentifier = *rclsid; - newClass->apartment_id = apt->oxid; - newClass->runContext = dwClsContext; - newClass->connectFlags = flags; - newClass->RpcRegistration = NULL; - - if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie ))) - newClass->dwCookie = InterlockedIncrement( &next_cookie ); - - /* - * Since we're making a copy of the object pointer, we have to increase its - * reference count. - */ - newClass->classObject = pUnk; - IUnknown_AddRef(newClass->classObject); - - EnterCriticalSection( &csRegisteredClassList ); - list_add_tail(&RegisteredClassList, &newClass->entry); - LeaveCriticalSection( &csRegisteredClassList ); - - *lpdwRegister = newClass->dwCookie; - - if (dwClsContext & CLSCTX_LOCAL_SERVER) { - IStream *marshal_stream; - - hr = apartment_get_local_server_stream(apt, &marshal_stream); - if(FAILED(hr)) - { - apartment_release(apt); - return hr; - } - - hr = RPC_StartLocalServer(&newClass->classIdentifier, - marshal_stream, - flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE), - &newClass->RpcRegistration); - IStream_Release(marshal_stream); - } - apartment_release(apt); - return S_OK; -} - /*********************************************************************** * CoResumeClassObjects (OLE32.@) * @@ -1295,67 +996,6 @@ HRESULT WINAPI CoSuspendClassObjects(void) return S_OK; }
-/*********************************************************************** - * CoAddRefServerProcess [OLE32.@] - * - * Helper function for incrementing the reference count of a local-server - * process. - * - * RETURNS - * New reference count. - * - * SEE ALSO - * CoReleaseServerProcess(). - */ -ULONG WINAPI CoAddRefServerProcess(void) -{ - ULONG refs; - - TRACE("\n"); - - EnterCriticalSection(&csRegisteredClassList); - refs = ++s_COMServerProcessReferences; - LeaveCriticalSection(&csRegisteredClassList); - - TRACE("refs before: %d\n", refs - 1); - - return refs; -} - -/*********************************************************************** - * CoReleaseServerProcess [OLE32.@] - * - * Helper function for decrementing the reference count of a local-server - * process. - * - * RETURNS - * New reference count. - * - * NOTES - * When reference count reaches 0, this function suspends all registered - * classes so no new connections are accepted. - * - * SEE ALSO - * CoAddRefServerProcess(), CoSuspendClassObjects(). - */ -ULONG WINAPI CoReleaseServerProcess(void) -{ - ULONG refs; - - TRACE("\n"); - - EnterCriticalSection(&csRegisteredClassList); - - refs = --s_COMServerProcessReferences; - /* FIXME: if (!refs) COM_SuspendClassObjects(); */ - - LeaveCriticalSection(&csRegisteredClassList); - - TRACE("refs after: %d\n", refs); - - return refs; -} - /*********************************************************************** * CoIsHandlerConnected [OLE32.@] * @@ -1683,7 +1323,6 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved) if (reserved) break; release_std_git(); RPC_UnregisterAllChannelHooks(); - DeleteCriticalSection(&csRegisteredClassList); apartment_global_cleanup(); break;
diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index 7a571352d32..e68d7b3b3da 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -223,12 +223,8 @@ HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, DWORD dest_context, void *dest_context_data, IRpcChannelBuffer **chan, struct apartment *apt) DECLSPEC_HIDDEN; HRESULT RPC_CreateServerChannel(DWORD dest_context, void *dest_context_data, IRpcChannelBuffer **chan) DECLSPEC_HIDDEN; -void RPC_ExecuteCall(struct dispatch_params *params) DECLSPEC_HIDDEN; HRESULT RPC_RegisterInterface(REFIID riid) DECLSPEC_HIDDEN; void RPC_UnregisterInterface(REFIID riid, BOOL wait) DECLSPEC_HIDDEN; -HRESULT RPC_StartLocalServer(REFCLSID clsid, IStream *stream, BOOL multi_use, void **registration) DECLSPEC_HIDDEN; -void RPC_StopLocalServer(void *registration) DECLSPEC_HIDDEN; -HRESULT RPC_GetLocalClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv) DECLSPEC_HIDDEN; HRESULT RPC_RegisterChannelHook(REFGUID rguid, IChannelHook *hook) DECLSPEC_HIDDEN; void RPC_UnregisterAllChannelHooks(void) DECLSPEC_HIDDEN; HRESULT RPC_ResolveOxid(OXID oxid, OXID_INFO *oxid_info) DECLSPEC_HIDDEN; @@ -254,10 +250,6 @@ extern struct apartment * WINAPI apartment_get_current_or_mta(void) DECLSPEC_HID extern HRESULT WINAPI apartment_get_local_server_stream(struct apartment *apt, IStream **ret) DECLSPEC_HIDDEN; extern void WINAPI apartment_global_cleanup(void) DECLSPEC_HIDDEN;
-HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid, - DWORD dwClsContext, IUnknown **ppUnk) DECLSPEC_HIDDEN; -void COM_RevokeAllClasses(const struct apartment *apt) DECLSPEC_HIDDEN; - /* DCOM messages used by the apartment window (not compatible with native) */ #define DM_EXECUTERPC (WM_USER + 0) /* WPARAM = 0, LPARAM = (struct dispatch_params *) */ #define DM_HOSTOBJECT (WM_USER + 1) /* WPARAM = 0, LPARAM = (struct host_object_params *) */ diff --git a/dlls/ole32/ole32.spec b/dlls/ole32/ole32.spec index c4e7b594fb2..ca22e4c8f1a 100644 --- a/dlls/ole32/ole32.spec +++ b/dlls/ole32/ole32.spec @@ -6,7 +6,7 @@ @ stdcall CLSIDFromProgID(wstr ptr) combase.CLSIDFromProgID @ stdcall CLSIDFromProgIDEx(wstr ptr) combase.CLSIDFromProgIDEx @ stdcall CLSIDFromString(wstr ptr) combase.CLSIDFromString -@ stdcall CoAddRefServerProcess() +@ stdcall CoAddRefServerProcess() combase.CoAddRefServerProcess @ stdcall CoAllowSetForegroundWindow(ptr ptr) @ stdcall CoBuildVersion() @ stdcall CoCopyProxy(ptr ptr) combase.CoCopyProxy @@ -65,7 +65,7 @@ @ stdcall CoQueryProxyBlanket(ptr ptr ptr ptr ptr ptr ptr ptr) combase.CoQueryProxyBlanket @ stub CoQueryReleaseObject @ stdcall CoRegisterChannelHook(ptr ptr) -@ stdcall CoRegisterClassObject(ptr ptr long long ptr) +@ stdcall CoRegisterClassObject(ptr ptr long long ptr) combase.CoRegisterClassObject @ stdcall CoRegisterInitializeSpy(ptr ptr) combase.CoRegisterInitializeSpy @ stdcall CoRegisterMallocSpy(ptr) combase.CoRegisterMallocSpy @ stdcall CoRegisterMessageFilter(ptr ptr) combase.CoRegisterMessageFilter @@ -73,10 +73,10 @@ @ stdcall CoRegisterSurrogate(ptr) @ stdcall CoRegisterSurrogateEx(ptr ptr) @ stdcall CoReleaseMarshalData(ptr) -@ stdcall CoReleaseServerProcess() +@ stdcall CoReleaseServerProcess() combase.CoReleaseServerProcess @ stdcall CoResumeClassObjects() @ stdcall CoRevertToSelf() combase.CoRevertToSelf -@ stdcall CoRevokeClassObject(long) +@ stdcall CoRevokeClassObject(long) combase.CoRevokeClassObject @ stdcall CoRevokeInitializeSpy(int64) combase.CoRevokeInitializeSpy @ stdcall CoRevokeMallocSpy() combase.CoRevokeMallocSpy @ stdcall CoSetProxyBlanket(ptr long long ptr long long ptr long) combase.CoSetProxyBlanket @@ -298,8 +298,6 @@ @ stdcall WriteFmtUserTypeStg(ptr long ptr) @ stub WriteOleStg @ stub WriteStringStream -@ stdcall InternalGetRegisteredClassObject(ptr ptr long ptr) -@ stdcall InternalRevokeAllClasses(ptr) @ stdcall Internal_apartment_disconnectproxies(ptr) @ stdcall Internal_RPC_ExecuteCall(ptr) @ stdcall Internal_stub_manager_int_release(ptr) diff --git a/dlls/ole32/rpc.c b/dlls/ole32/rpc.c index eb76d9cb668..84d26c70c6c 100644 --- a/dlls/ole32/rpc.c +++ b/dlls/ole32/rpc.c @@ -1648,182 +1648,3 @@ void RPC_StartRemoting(struct apartment *apt) } start_apartment_remote_unknown(apt); } - -static void get_localserver_pipe_name(WCHAR *pipefn, REFCLSID rclsid) -{ - static const WCHAR wszPipeRef[] = {'\','\','.','\','p','i','p','e','\',0}; - lstrcpyW(pipefn, wszPipeRef); - StringFromGUID2(rclsid, pipefn + ARRAY_SIZE(wszPipeRef) - 1, CHARS_IN_GUID); -} - -struct local_server_params -{ - CLSID clsid; - IStream *stream; - HANDLE pipe; - HANDLE stop_event; - HANDLE thread; - BOOL multi_use; -}; - -/* FIXME: should call to rpcss instead */ -static DWORD WINAPI local_server_thread(LPVOID param) -{ - struct local_server_params * lsp = param; - WCHAR pipefn[100]; - HRESULT hres; - IStream *pStm = lsp->stream; - STATSTG ststg; - unsigned char *buffer; - int buflen; - LARGE_INTEGER seekto; - ULARGE_INTEGER newpos; - ULONG res; - BOOL multi_use = lsp->multi_use; - OVERLAPPED ovl; - HANDLE pipe_event, hPipe = lsp->pipe, new_pipe; - DWORD bytes; - - TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid)); - - memset(&ovl, 0, sizeof(ovl)); - get_localserver_pipe_name(pipefn, &lsp->clsid); - ovl.hEvent = pipe_event = CreateEventW(NULL, FALSE, FALSE, NULL); - - while (1) { - if (!ConnectNamedPipe(hPipe, &ovl)) - { - DWORD error = GetLastError(); - if (error == ERROR_IO_PENDING) - { - HANDLE handles[2] = { pipe_event, lsp->stop_event }; - DWORD ret; - ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE); - if (ret != WAIT_OBJECT_0) - break; - } - /* client already connected isn't an error */ - else if (error != ERROR_PIPE_CONNECTED) - { - ERR("ConnectNamedPipe failed with error %d\n", GetLastError()); - break; - } - } - - TRACE("marshalling LocalServer to client\n"); - - hres = IStream_Stat(pStm,&ststg,STATFLAG_NONAME); - if (hres != S_OK) - break; - - seekto.u.LowPart = 0; - seekto.u.HighPart = 0; - hres = IStream_Seek(pStm,seekto,STREAM_SEEK_SET,&newpos); - if (hres != S_OK) { - FIXME("IStream_Seek failed, %x\n",hres); - break; - } - - buflen = ststg.cbSize.u.LowPart; - buffer = HeapAlloc(GetProcessHeap(),0,buflen); - - hres = IStream_Read(pStm,buffer,buflen,&res); - if (hres != S_OK) { - FIXME("Stream Read failed, %x\n",hres); - HeapFree(GetProcessHeap(),0,buffer); - break; - } - - WriteFile(hPipe,buffer,buflen,&res,&ovl); - GetOverlappedResult(hPipe, &ovl, &bytes, TRUE); - HeapFree(GetProcessHeap(),0,buffer); - - FlushFileBuffers(hPipe); - DisconnectNamedPipe(hPipe); - TRACE("done marshalling LocalServer\n"); - - if (!multi_use) - { - TRACE("single use object, shutting down pipe %s\n", debugstr_w(pipefn)); - 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 ); - if (new_pipe == INVALID_HANDLE_VALUE) - { - FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError()); - 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, err; - struct local_server_params *lsp; - WCHAR pipefn[100]; - - lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp)); - if (!lsp) - return E_OUTOFMEMORY; - - lsp->clsid = *clsid; - lsp->stream = stream; - IStream_AddRef(stream); - lsp->stop_event = CreateEventW(NULL, FALSE, FALSE, NULL); - if (!lsp->stop_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->pipe); - CloseHandle(lsp->stop_event); - HeapFree(GetProcessHeap(), 0, lsp); - return HRESULT_FROM_WIN32(GetLastError()); - } - - *registration = lsp; - return S_OK; -} - -/* stops listening for a local server */ -void RPC_StopLocalServer(void *registration) -{ - struct local_server_params *lsp = registration; - - /* signal local_server_thread to stop */ - SetEvent(lsp->stop_event); - /* wait for it to exit */ - WaitForSingleObject(lsp->thread, INFINITE); - - IStream_Release(lsp->stream); - CloseHandle(lsp->stop_event); - CloseHandle(lsp->thread); - HeapFree(GetProcessHeap(), 0, lsp); -}