Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ole32/compobj.c | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-)
diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index 1c7645b..a3b4598 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -734,6 +734,19 @@ static APARTMENT *apartment_find_mta(void) return apt; }
+/* Return the current apartment if it exists, or, failing that, the MTA. Caller + * must free the returned apartment in either case. */ +static APARTMENT *apartment_get_current_or_mta(void) +{ + APARTMENT *apt = COM_CurrentApt(); + if (apt) + { + apartment_addref(apt); + return apt; + } + return apartment_find_mta(); +} + static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass) { list_remove(&curClass->entry); @@ -2997,15 +3010,10 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(
*ppv = NULL;
- if ((apt = COM_CurrentApt())) - apartment_addref(apt); - else + if (!(apt = apartment_get_current_or_mta())) { - if (!(apt = apartment_find_mta())) - { - ERR("apartment not initialised\n"); - return CO_E_NOTINITIALIZED; - } + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; }
if (pServerInfo) { @@ -3298,15 +3306,12 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx( if(FAILED(hres)) clsid = *rclsid;
- if (!(apt = COM_CurrentApt())) + if (!(apt = apartment_get_current_or_mta())) { - if (!(apt = apartment_find_mta())) - { - ERR("apartment not initialised\n"); - return CO_E_NOTINITIALIZED; - } - apartment_release(apt); + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; } + apartment_release(apt);
/* * The Standard Global Interface Table (GIT) object is a process-wide singleton. @@ -4998,22 +5003,19 @@ HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv) HRESULT WINAPI CoGetContextToken( ULONG_PTR *token ) { struct oletls *info = COM_CurrentInfo(); + APARTMENT *apt;
TRACE("(%p)\n", token);
if (!info) return E_OUTOFMEMORY;
- if (!info->apt) + if (!(apt = apartment_get_current_or_mta())) { - APARTMENT *apt; - if (!(apt = apartment_find_mta())) - { - ERR("apartment not initialised\n"); - return CO_E_NOTINITIALIZED; - } - apartment_release(apt); + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; } + apartment_release(apt);
if (!token) return E_POINTER;
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ole32/compobj.c | 43 ++++++++++++++++++++++++++++++------------- dlls/ole32/tests/compobj.c | 24 ++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 13 deletions(-)
diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index a3b4598..ca91848 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -1089,8 +1089,7 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject(
TRACE("(%08x)\n",dwRegister);
- apt = COM_CurrentApt(); - if (!apt) + if (!(apt = apartment_get_current_or_mta())) { ERR("COM was not initialized\n"); return CO_E_NOTINITIALIZED; @@ -1121,7 +1120,7 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject( }
LeaveCriticalSection( &csRegisteredClassList ); - + apartment_release(apt); return hr; }
@@ -2072,9 +2071,11 @@ HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved ) return hr; }
- apt = COM_CurrentApt(); - if (!apt) + if (!(apt = apartment_get_current_or_mta())) + { + ERR("apartment not initialised\n"); return CO_E_NOTINITIALIZED; + }
manager = get_stub_manager_from_object(apt, lpUnk, FALSE); if (manager) { @@ -2089,6 +2090,7 @@ HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved ) * not found, making apps think that the object was disconnected, when * it actually wasn't */
+ apartment_release(apt); return S_OK; }
@@ -2596,7 +2598,7 @@ HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid) static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\',0}; static const WCHAR wszPSC[] = {'\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0}; WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)]; - APARTMENT *apt = COM_CurrentApt(); + APARTMENT *apt; struct registered_psclsid *registered_psclsid; ACTCTX_SECTION_KEYED_DATA data; HRESULT hr; @@ -2605,11 +2607,12 @@ HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
- if (!apt) + if (!(apt = apartment_get_current_or_mta())) { ERR("apartment not initialised\n"); return CO_E_NOTINITIALIZED; } + apartment_release(apt);
if (!pclsid) return E_INVALIDARG; @@ -2680,16 +2683,17 @@ HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid) */ HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid) { - APARTMENT *apt = COM_CurrentApt(); + APARTMENT *apt; struct registered_psclsid *registered_psclsid;
TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
- if (!apt) + if (!(apt = apartment_get_current_or_mta())) { ERR("apartment not initialised\n"); return CO_E_NOTINITIALIZED; } + apartment_release(apt);
EnterCriticalSection(&cs_registered_psclsid_list);
@@ -2815,8 +2819,7 @@ HRESULT WINAPI CoRegisterClassObject( if ( (lpdwRegister==0) || (pUnk==0) ) return E_INVALIDARG;
- apt = COM_CurrentApt(); - if (!apt) + if (!(apt = apartment_get_current_or_mta())) { ERR("COM was not initialized\n"); return CO_E_NOTINITIALIZED; @@ -2839,16 +2842,21 @@ HRESULT WINAPI CoRegisterClassObject( 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; @@ -2877,7 +2885,10 @@ HRESULT WINAPI CoRegisterClassObject(
hr = get_local_server_stream(apt, &marshal_stream); if(FAILED(hr)) + { + apartment_release(apt); return hr; + }
hr = RPC_StartLocalServer(&newClass->classIdentifier, marshal_stream, @@ -2885,6 +2896,7 @@ HRESULT WINAPI CoRegisterClassObject( &newClass->RpcRegistration); IStream_Release(marshal_stream); } + apartment_release(apt); return S_OK; }
@@ -3645,8 +3657,11 @@ HRESULT WINAPI CoLockObjectExternal( TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n", pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
- apt = COM_CurrentApt(); - if (!apt) return CO_E_NOTINITIALIZED; + if (!(apt = apartment_get_current_or_mta())) + { + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; + }
stubmgr = get_stub_manager_from_object(apt, pUnk, fLock); if (!stubmgr) @@ -3655,6 +3670,7 @@ HRESULT WINAPI CoLockObjectExternal( /* Note: native is pretty broken here because it just silently * fails, without returning an appropriate error code, making apps * think that the object was disconnected, when it actually wasn't */ + apartment_release(apt); return S_OK; }
@@ -3664,6 +3680,7 @@ HRESULT WINAPI CoLockObjectExternal( stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
stub_manager_int_release(stubmgr); + apartment_release(apt); return S_OK; }
diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c index 0ce941b..ecfbac8 100644 --- a/dlls/ole32/tests/compobj.c +++ b/dlls/ole32/tests/compobj.c @@ -3701,6 +3701,8 @@ static DWORD CALLBACK implicit_mta_proc(void *param) IComThreadingInfo *threading_info; ULONG_PTR token; IUnknown *unk; + DWORD cookie; + CLSID clsid; HRESULT hr;
test_apt_type(APTTYPE_MTA, APTTYPEQUALIFIER_IMPLICIT_MTA, TRUE, TRUE); @@ -3720,6 +3722,28 @@ static DWORD CALLBACK implicit_mta_proc(void *param) hr = CoGetContextToken(&token); ok_ole_success(hr, "CoGetContextToken");
+ hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer); + ok_ole_success(hr, "CoRegisterPSClsid"); + + hr = CoGetPSClsid(&IID_IClassFactory, &clsid); + ok_ole_success(hr, "CoGetPSClsid"); + + hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&Test_ClassFactory, + CLSCTX_INPROC_SERVER, REGCLS_SINGLEUSE, &cookie); + ok_ole_success(hr, "CoRegisterClassObject"); + + hr = CoRevokeClassObject(cookie); + ok_ole_success(hr, "CoRevokeClassObject"); + + hr = CoRegisterMessageFilter(NULL, NULL); + ok(hr == CO_E_NOT_SUPPORTED, "got %#x\n", hr); + + hr = CoLockObjectExternal((IUnknown *)&Test_Unknown, TRUE, TRUE); + ok_ole_success(hr, "CoLockObjectExternal"); + + hr = CoDisconnectObject((IUnknown *)&Test_Unknown, 0); + ok_ole_success(hr, "CoDisconnectObject"); + return 0; }
Signed-off-by: Huw Davies huw@codeweavers.com
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ole32/compobj.c | 10 +++++++++- dlls/ole32/tests/compobj.c | 19 ++++++++----------- 2 files changed, 17 insertions(+), 12 deletions(-)
diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index ca91848..9cbfaee 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -5108,8 +5108,9 @@ HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier) { struct oletls *info = COM_CurrentInfo(); + APARTMENT *apt;
- FIXME("(%p, %p): semi-stub\n", type, qualifier); + TRACE("(%p, %p)\n", type, qualifier);
if (!type || !qualifier) return E_INVALIDARG; @@ -5128,6 +5129,13 @@ HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier)
*qualifier = APTTYPEQUALIFIER_NONE;
+ if (!info->apt && (apt = apartment_find_mta())) + { + apartment_release(apt); + *type = APTTYPE_MTA; + *qualifier = APTTYPEQUALIFIER_IMPLICIT_MTA; + } + return info->apt ? S_OK : CO_E_NOTINITIALIZED; }
diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c index ecfbac8..b9b7be0 100644 --- a/dlls/ole32/tests/compobj.c +++ b/dlls/ole32/tests/compobj.c @@ -602,9 +602,8 @@ static void test_StringFromGUID2(void) ok(len == 0, "len: %d (expected 0)\n", len); }
-#define test_apt_type(t, q, t_t, t_q) _test_apt_type(t, q, t_t, t_q, __LINE__) -static void _test_apt_type(APTTYPE expected_type, APTTYPEQUALIFIER expected_qualifier, BOOL todo_type, - BOOL todo_qualifier, int line) +#define test_apt_type(t, q) _test_apt_type(t, q, __LINE__) +static void _test_apt_type(APTTYPE expected_type, APTTYPEQUALIFIER expected_qualifier, int line) { APTTYPEQUALIFIER qualifier = ~0u; APTTYPE type = ~0u; @@ -615,9 +614,7 @@ static void _test_apt_type(APTTYPE expected_type, APTTYPEQUALIFIER expected_qual
hr = pCoGetApartmentType(&type, &qualifier); ok_(__FILE__, line)(hr == S_OK || hr == CO_E_NOTINITIALIZED, "Unexpected return code: 0x%08x\n", hr); -todo_wine_if(todo_type) ok_(__FILE__, line)(type == expected_type, "Wrong apartment type %d, expected %d\n", type, expected_type); -todo_wine_if(todo_qualifier) ok_(__FILE__, line)(qualifier == expected_qualifier, "Wrong apartment qualifier %d, expected %d\n", qualifier, expected_qualifier); } @@ -660,7 +657,7 @@ static void test_CoCreateInstance(void) hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk); ok(hr == CO_E_NOTINITIALIZED, "CoCreateInstance should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
- test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE); + test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE); }
static void test_CoGetClassObject(void) @@ -682,7 +679,7 @@ static void test_CoGetClassObject(void) broken(hr == CO_E_NOTINITIALIZED), /* win9x */ "CoGetClassObject should have returned E_INVALIDARG instead of 0x%08x\n", hr);
- test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE); + test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE);
if (!pRegOverridePredefKey) { @@ -1797,7 +1794,7 @@ static void test_CoGetObjectContext(void)
pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
- test_apt_type(APTTYPE_MAINSTA, APTTYPEQUALIFIER_NONE, FALSE, FALSE); + test_apt_type(APTTYPE_MAINSTA, APTTYPEQUALIFIER_NONE);
hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo); ok_ole_success(hr, "CoGetObjectContext"); @@ -1993,11 +1990,11 @@ static void test_CoGetContextToken(void) ok(hr == CO_E_NOTINITIALIZED, "Expected CO_E_NOTINITIALIZED, got 0x%08x\n", hr); ok(token == 0xdeadbeef, "Expected 0, got 0x%lx\n", token);
- test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE); + test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE);
CoInitialize(NULL);
- test_apt_type(APTTYPE_MAINSTA, APTTYPEQUALIFIER_NONE, FALSE, FALSE); + test_apt_type(APTTYPE_MAINSTA, APTTYPEQUALIFIER_NONE);
hr = pCoGetContextToken(NULL); ok(hr == E_POINTER, "Expected E_POINTER, got 0x%08x\n", hr); @@ -3705,7 +3702,7 @@ static DWORD CALLBACK implicit_mta_proc(void *param) CLSID clsid; HRESULT hr;
- test_apt_type(APTTYPE_MTA, APTTYPEQUALIFIER_IMPLICIT_MTA, TRUE, TRUE); + test_apt_type(APTTYPE_MTA, APTTYPEQUALIFIER_IMPLICIT_MTA);
hr = CoCreateInstance(&CLSID_InternetZoneManager, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&unk); ok_ole_success(hr, "CoCreateInstance");
Signed-off-by: Huw Davies huw@codeweavers.com
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ole32/tests/compobj.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c index b9b7be0..c43e86c 100644 --- a/dlls/ole32/tests/compobj.c +++ b/dlls/ole32/tests/compobj.c @@ -2998,14 +2998,36 @@ static void test_CoWaitForMultipleHandles(void) ok(index == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); CloseHandle(thread);
+ CoUninitialize(); + + /* If COM was not initialized, messages are neither pumped nor peeked at */ + PostMessageA(hWnd, WM_DDE_FIRST, 0, 0); + hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index); + ok(hr == RPC_S_CALLPENDING, "got %#x\n", hr); + success = MsgWaitForMultipleObjectsEx(0, NULL, 2, QS_ALLPOSTMESSAGE, MWMO_ALERTABLE); + ok(success == 0, "MsgWaitForMultipleObjects returned %x\n", success); + success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE); + ok(success, "PeekMessage failed: %u\n", GetLastError()); + + /* same in an MTA */ + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + PostMessageA(hWnd, WM_DDE_FIRST, 0, 0); + hr = CoWaitForMultipleHandles(0, 100, 2, handles, &index); + ok(hr == RPC_S_CALLPENDING, "got %#x\n", hr); + success = MsgWaitForMultipleObjectsEx(0, NULL, 2, QS_ALLPOSTMESSAGE, MWMO_ALERTABLE); + ok(success == 0, "MsgWaitForMultipleObjects returned %x\n", success); + success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE); + ok(success, "PeekMessage failed: %u\n", GetLastError()); + + CoUninitialize(); + CloseHandle(handles[0]); CloseHandle(handles[1]); DestroyWindow(hWnd);
success = UnregisterClassA(cls_name, GetModuleHandleA(0)); ok(success, "UnregisterClass failed %u\n", GetLastError()); - - CoUninitialize(); }
static void test_CoGetMalloc(void)
Signed-off-by: Huw Davies huw@codeweavers.com
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ole32/compobj.c | 2 +- dlls/ole32/compobj_private.h | 3 +- dlls/ole32/marshal.c | 32 ++++++++---- dlls/ole32/rpc.c | 12 +++-- dlls/ole32/tests/marshal.c | 114 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 148 insertions(+), 15 deletions(-)
diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index 9cbfaee..fd5cbde 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -736,7 +736,7 @@ static APARTMENT *apartment_find_mta(void)
/* Return the current apartment if it exists, or, failing that, the MTA. Caller * must free the returned apartment in either case. */ -static APARTMENT *apartment_get_current_or_mta(void) +APARTMENT *apartment_get_current_or_mta(void) { APARTMENT *apt = COM_CurrentApt(); if (apt) diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index 12413f7..dc09d20 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -212,7 +212,7 @@ void RPC_StartRemoting(struct apartment *apt) DECLSPEC_HIDDEN; HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, const OXID_INFO *oxid_info, DWORD dest_context, void *dest_context_data, - IRpcChannelBuffer **chan) DECLSPEC_HIDDEN; + IRpcChannelBuffer **chan, 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; @@ -248,6 +248,7 @@ HRESULT apartment_createwindowifneeded(struct apartment *apt) DECLSPEC_HIDDEN; HWND apartment_getwindow(const struct apartment *apt) DECLSPEC_HIDDEN; HRESULT enter_apartment(struct oletls *info, DWORD model) DECLSPEC_HIDDEN; void leave_apartment(struct oletls *info) DECLSPEC_HIDDEN; +APARTMENT *apartment_get_current_or_mta(void) 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 *) */ diff --git a/dlls/ole32/marshal.c b/dlls/ole32/marshal.c index b39dac0..822d06e 100644 --- a/dlls/ole32/marshal.c +++ b/dlls/ole32/marshal.c @@ -313,13 +313,15 @@ static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, UL * the interfaces were returned */ if (SUCCEEDED(hr)) { + APARTMENT *apt = apartment_get_current_or_mta(); + /* try to unmarshal each object returned to us */ for (i = 0; i < nonlocal_mqis; i++) { ULONG index = mapping[i]; HRESULT hrobj = qiresults[i].hResult; if (hrobj == S_OK) - hrobj = unmarshal_object(&qiresults[i].std, COM_CurrentApt(), + hrobj = unmarshal_object(&qiresults[i].std, apt, This->dest_context, This->dest_context_data, pMQIs[index].pIID, &This->oxid_info, @@ -331,6 +333,8 @@ static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, UL ERR("Failed to get pointer to interface %s\n", debugstr_guid(pMQIs[index].pIID)); pMQIs[index].hr = hrobj; } + + apartment_release(apt); }
/* free the memory allocated by the proxy */ @@ -1010,8 +1014,7 @@ static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnk if (This->sorflags & SORFP_NOLIFETIMEMGMT) return S_FALSE;
- apt = COM_CurrentApt(); - if (!apt) + if (!(apt = apartment_get_current_or_mta())) return CO_E_NOTINITIALIZED;
called_in_original_apt = This->parent && (This->parent->oxid == apt->oxid); @@ -1046,7 +1049,7 @@ static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnk stdobjref.ipid = This->oxid_info.ipidRemUnknown;
/* do the unmarshal */ - hr = unmarshal_object(&stdobjref, COM_CurrentApt(), This->dest_context, + hr = unmarshal_object(&stdobjref, apt, This->dest_context, This->dest_context_data, &IID_IRemUnknown, &This->oxid_info, (void**)remunk); if (hr == S_OK && called_in_original_apt) @@ -1056,6 +1059,7 @@ static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnk } } LeaveCriticalSection(&This->cs); + apartment_release(apt);
TRACE("got IRemUnknown* pointer %p, hr = 0x%08x\n", *remunk, hr);
@@ -1288,7 +1292,7 @@ static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, &proxy_manager->oxid_info, proxy_manager->dest_context, proxy_manager->dest_context_data, - &chanbuf); + &chanbuf, apt); if (hr == S_OK) hr = proxy_manager_create_ifproxy(proxy_manager, stdobjref, riid, chanbuf, &ifproxy); @@ -1324,14 +1328,14 @@ StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, v STDOBJREF stdobjref; ULONG res; HRESULT hres; - APARTMENT *apt = COM_CurrentApt(); + APARTMENT *apt; APARTMENT *stub_apt; OXID oxid;
TRACE("(...,%s,....)\n", debugstr_guid(riid));
/* we need an apartment to unmarshal into */ - if (!apt) + if (!(apt = apartment_get_current_or_mta())) { ERR("Apartment not initialized\n"); return CO_E_NOTINITIALIZED; @@ -1339,10 +1343,18 @@ StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, v
/* read STDOBJREF from wire */ hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res); - if (hres != S_OK) return STG_E_READFAULT; + if (hres != S_OK) + { + apartment_release(apt); + return STG_E_READFAULT; + }
hres = apartment_getoxid(apt, &oxid); - if (hres != S_OK) return hres; + if (hres != S_OK) + { + apartment_release(apt); + return hres; + }
/* check if we're marshalling back to ourselves */ if ((oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid))) @@ -1357,6 +1369,7 @@ StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, v stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs, stdobjref.flags & SORFP_TABLEWEAK, FALSE);
stub_manager_int_release(stubmgr); + apartment_release(apt); return hres; }
@@ -1395,6 +1408,7 @@ StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, v if (hres != S_OK) WARN("Failed with error 0x%08x\n", hres); else TRACE("Successfully created proxy %p\n", *ppv);
+ apartment_release(apt); return hres; }
diff --git a/dlls/ole32/rpc.c b/dlls/ole32/rpc.c index 8d8276e..5a7626b 100644 --- a/dlls/ole32/rpc.c +++ b/dlls/ole32/rpc.c @@ -830,14 +830,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 +847,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 +970,7 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac
TRACE("-- 0x%08x\n", hr);
+ apartment_release(apt); return hr; }
@@ -1094,7 +1098,7 @@ static const IRpcChannelBufferVtbl ServerRpcChannelBufferVtbl = HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, const OXID_INFO *oxid_info, DWORD dest_context, void *dest_context_data, - IRpcChannelBuffer **chan) + IRpcChannelBuffer **chan, APARTMENT *apt) { ClientRpcChannelBuffer *This; WCHAR endpoint[200]; @@ -1148,7 +1152,7 @@ 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;
diff --git a/dlls/ole32/tests/marshal.c b/dlls/ole32/tests/marshal.c index 12c46e9..c5c69f0 100644 --- a/dlls/ole32/tests/marshal.c +++ b/dlls/ole32/tests/marshal.c @@ -3419,6 +3419,119 @@ static void test_manualresetevent(void) ok(!ref, "Got nonzero ref: %d\n", ref); }
+static DWORD CALLBACK implicit_mta_unmarshal_proc(void *param) +{ + IStream *stream = param; + IClassFactory *cf; + IUnknown *proxy; + HRESULT hr; + + IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL); + hr = CoUnmarshalInterface(stream, &IID_IClassFactory, (void **)&cf); + ok_ole_success(hr, CoUnmarshalInterface); + + hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy); + ok_ole_success(hr, IClassFactory_CreateInstance); + + IUnknown_Release(proxy); + + /* But if we initialize an STA in this apartment, it becomes the wrong one. */ + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy); + ok(hr == RPC_E_WRONG_THREAD, "got %#x\n", hr); + + CoUninitialize(); + + ok_more_than_one_lock(); + ok_non_zero_external_conn(); + + IClassFactory_Release(cf); + + ok_no_locks(); + ok_zero_external_conn(); + ok_last_release_closes(TRUE); + return 0; +} + +static DWORD CALLBACK implicit_mta_use_proc(void *param) +{ + IClassFactory *cf = param; + IUnknown *proxy; + HRESULT hr; + + hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy); + ok_ole_success(hr, IClassFactory_CreateInstance); + + IUnknown_Release(proxy); + + /* But if we initialize an STA in this apartment, it becomes the wrong one. */ + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy); + ok(hr == RPC_E_WRONG_THREAD, "got %#x\n", hr); + + CoUninitialize(); + return 0; +} + +static void test_implicit_mta(void) +{ + HANDLE host_thread, thread; + IClassFactory *cf; + IStream *stream; + HRESULT hr; + DWORD tid; + + cLocks = 0; + external_connections = 0; + + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + /* Firstly: we can unmarshal and use an object while in the implicit MTA. */ + hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); + ok_ole_success(hr, CreateStreamOnHGlobal); + tid = start_host_object(stream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread); + + ok_more_than_one_lock(); + ok_non_zero_external_conn(); + + thread = CreateThread(NULL, 0, implicit_mta_unmarshal_proc, stream, 0, NULL); + ok(!WaitForSingleObject(thread, 1000), "wait failed\n"); + CloseHandle(thread); + + IStream_Release(stream); + end_host_object(tid, host_thread); + + /* Secondly: we can unmarshal an object into the real MTA and then use it + * from the implicit MTA. */ + hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); + ok_ole_success(hr, CreateStreamOnHGlobal); + tid = start_host_object(stream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread); + + ok_more_than_one_lock(); + ok_non_zero_external_conn(); + + IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL); + hr = CoUnmarshalInterface(stream, &IID_IClassFactory, (void **)&cf); + ok_ole_success(hr, CoUnmarshalInterface); + + thread = CreateThread(NULL, 0, implicit_mta_use_proc, cf, 0, NULL); + ok(!WaitForSingleObject(thread, 1000), "wait failed\n"); + CloseHandle(thread); + + IClassFactory_Release(cf); + IStream_Release(stream); + + ok_no_locks(); + ok_non_zero_external_conn(); + ok_last_release_closes(TRUE); + + end_host_object(tid, host_thread); + + CoUninitialize(); +} + static const char *debugstr_iid(REFIID riid) { static char name[256]; @@ -3765,6 +3878,7 @@ START_TEST(marshal) register_test_window();
test_cocreateinstance_proxy(); + test_implicit_mta();
pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
On 09/04/18 21:15, Zebediah Figura wrote:
Signed-off-by: Zebediah Figura z.figura12@gmail.com
dlls/ole32/compobj.c | 2 +- dlls/ole32/compobj_private.h | 3 +- dlls/ole32/marshal.c | 32 ++++++++---- dlls/ole32/rpc.c | 12 +++-- dlls/ole32/tests/marshal.c | 114 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 148 insertions(+), 15 deletions(-)
Repasting my earlier note here since I forgot to edit the patch:
----
This patch results in some good news and some bad news for bug 18070.
The good news is that we can unmarshal into literally any thread—uninitialized, STA, or MTA—as long as there's an MTA somewhere else in the process. This means we can use a COM proxy on any thread. The bad news is that we can't change threading models (i.e. initialize or uninitialize COM on a thread) while we're doing this, or ole32 will throw up RPC_E_WRONG_THREAD when we try to make a proxy call.
The symptoms of bug 18070 show that there has to exist an MTA in the process, but that COM can't be initialized on the thread itself: "It is up to the custom action to initialize COM to its liking." This fits the MTA condition quite nicely, but then runs into the separate problem that the custom action can change the threading model on us.
What this means is that we can't keep proxies around on the custom action's thread and then just run all calls to MSI functions through them, since they might go bad at any point. I see at least two solutions to this:
(1) Keep the COM objects on a different thread (probably just the thread that the MTA is initialized on). Then use a dedicated 'pipe' thread to thunk callbacks to the MTA thread, whence they will then be converted into proxy calls.
(2) Instead of keeping COM objects around during the entire custom action, create and then release one generic 'server' object every time an MSI function is called. This will, of course, work regardless of what threading model the custom action's thread is actively using, since it won't change during the course of the call.
(3) Along the same lines as (2), but potentially even simpler: use the RPC APIs directly. That is, replace our IWineMsiRemotePackage_GetProperty(...) with a simpler remote_GetProperty(...) that does about the same thing, but without the overhead of going through ole32. (And for all the work I did to make ole32 work right! But it is for the best.)
I'm most inclined towards (3)—I think it'll be the solution with the least overhead, and it won't take too much work to convert from what we have.
Therefore: if anyone has any alternate preferences, reasons why one or more of the above won't work, or general feedback, please speak now. Alternatively, wait until I've done all the work to convert everything to RPC server stubs, and then tell me why it all won't work ;-)
Signed-off-by: Huw Davies huw@codeweavers.com
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ole32/compobj_private.h | 2 +- dlls/ole32/marshal.c | 5 +++-- dlls/ole32/rpc.c | 2 +- dlls/ole32/stubmanager.c | 3 +-- dlls/ole32/tests/marshal.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 56 insertions(+), 6 deletions(-)
diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index dc09d20..212d328 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -200,7 +200,7 @@ void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs, const void stub_manager_disconnect(struct stub_manager *m) DECLSPEC_HIDDEN; HRESULT ipid_get_dispatch_params(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **manager, IRpcStubBuffer **stub, IRpcChannelBuffer **chan, IID *iid, IUnknown **iface) DECLSPEC_HIDDEN; -HRESULT start_apartment_remote_unknown(void) DECLSPEC_HIDDEN; +HRESULT start_apartment_remote_unknown(APARTMENT *apt) DECLSPEC_HIDDEN;
HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *obj, DWORD dest_context, void *dest_context_data, MSHLFLAGS mshlflags) DECLSPEC_HIDDEN;
diff --git a/dlls/ole32/marshal.c b/dlls/ole32/marshal.c index 822d06e..7c0f541 100644 --- a/dlls/ole32/marshal.c +++ b/dlls/ole32/marshal.c @@ -1225,11 +1225,11 @@ StdMarshalImpl_MarshalInterface( STDOBJREF stdobjref; ULONG res; HRESULT hres; - APARTMENT *apt = COM_CurrentApt(); + APARTMENT *apt;
TRACE("(...,%s,...)\n", debugstr_guid(riid));
- if (!apt) + if (!(apt = apartment_get_current_or_mta())) { ERR("Apartment not initialized\n"); return CO_E_NOTINITIALIZED; @@ -1239,6 +1239,7 @@ StdMarshalImpl_MarshalInterface( RPC_StartRemoting(apt);
hres = marshal_object(apt, &stdobjref, riid, pv, dest_context, dest_context_data, mshlflags); + apartment_release(apt); if (hres != S_OK) { ERR("Failed to create ifstub, hres=0x%x\n", hres); diff --git a/dlls/ole32/rpc.c b/dlls/ole32/rpc.c index 5a7626b..a73d23c 100644 --- a/dlls/ole32/rpc.c +++ b/dlls/ole32/rpc.c @@ -1648,7 +1648,7 @@ void RPC_StartRemoting(struct apartment *apt)
/* FIXME: move remote unknown exporting into this function */ } - start_apartment_remote_unknown(); + start_apartment_remote_unknown(apt); }
diff --git a/dlls/ole32/stubmanager.c b/dlls/ole32/stubmanager.c index 57048c6..75c4b04 100644 --- a/dlls/ole32/stubmanager.c +++ b/dlls/ole32/stubmanager.c @@ -812,11 +812,10 @@ static const IRemUnknownVtbl RemUnknown_Vtbl = };
/* starts the IRemUnknown listener for the current apartment */ -HRESULT start_apartment_remote_unknown(void) +HRESULT start_apartment_remote_unknown(APARTMENT *apt) { IRemUnknown *pRemUnknown; HRESULT hr = S_OK; - APARTMENT *apt = COM_CurrentApt();
EnterCriticalSection(&apt->cs); if (!apt->remunk_exported) diff --git a/dlls/ole32/tests/marshal.c b/dlls/ole32/tests/marshal.c index c5c69f0..e8558dd 100644 --- a/dlls/ole32/tests/marshal.c +++ b/dlls/ole32/tests/marshal.c @@ -3475,10 +3475,34 @@ static DWORD CALLBACK implicit_mta_use_proc(void *param) return 0; }
+struct implicit_mta_marshal_data +{ + IStream *stream; + HANDLE start; + HANDLE stop; +}; + +static DWORD CALLBACK implicit_mta_marshal_proc(void *param) +{ + struct implicit_mta_marshal_data *data = param; + HRESULT hr; + + hr = CoMarshalInterface(data->stream, &IID_IClassFactory, + (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + ok_ole_success(hr, CoMarshalInterface); + + SetEvent(data->start); + + ok(!WaitForSingleObject(data->stop, 1000), "wait failed\n"); + return 0; +} + static void test_implicit_mta(void) { + struct implicit_mta_marshal_data data; HANDLE host_thread, thread; IClassFactory *cf; + IUnknown *proxy; IStream *stream; HRESULT hr; DWORD tid; @@ -3529,6 +3553,32 @@ static void test_implicit_mta(void)
end_host_object(tid, host_thread);
+ /* Thirdly: we can marshal an object from the implicit MTA and then + * unmarshal it into the real one. */ + data.start = CreateEventA(NULL, FALSE, FALSE, NULL); + data.stop = CreateEventA(NULL, FALSE, FALSE, NULL); + + hr = CreateStreamOnHGlobal(NULL, TRUE, &data.stream); + ok_ole_success(hr, CreateStreamOnHGlobal); + + thread = CreateThread(NULL, 0, implicit_mta_marshal_proc, &data, 0, NULL); + ok(!WaitForSingleObject(data.start, 1000), "wait failed\n"); + + IStream_Seek(data.stream, ullZero, STREAM_SEEK_SET, NULL); + hr = CoUnmarshalInterface(data.stream, &IID_IClassFactory, (void **)&cf); + ok_ole_success(hr, CoUnmarshalInterface); + + hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy); + ok_ole_success(hr, IClassFactory_CreateInstance); + + IUnknown_Release(proxy); + + SetEvent(data.stop); + ok(!WaitForSingleObject(thread, 1000), "wait failed\n"); + CloseHandle(thread); + + IStream_Release(data.stream); + CoUninitialize(); }
Signed-off-by: Huw Davies huw@codeweavers.com