mirror of
https://github.com/reactos/reactos.git
synced 2025-01-01 03:54:02 +00:00
[OLE32_WINETEST] Sync with Wine Staging 3.9. CORE-14656
This commit is contained in:
parent
85037eb745
commit
a6cdf4ff08
3 changed files with 760 additions and 224 deletions
|
@ -608,28 +608,8 @@ static void test_StringFromGUID2(void)
|
|||
ok(len == 0, "len: %d (expected 0)\n", len);
|
||||
}
|
||||
|
||||
struct info
|
||||
{
|
||||
HANDLE wait, stop;
|
||||
};
|
||||
|
||||
static DWORD CALLBACK ole_initialize_thread(LPVOID pv)
|
||||
{
|
||||
HRESULT hr;
|
||||
struct info *info = pv;
|
||||
|
||||
hr = pCoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
|
||||
SetEvent(info->wait);
|
||||
WaitForSingleObject(info->stop, 10000);
|
||||
|
||||
CoUninitialize();
|
||||
return hr;
|
||||
}
|
||||
|
||||
#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;
|
||||
|
@ -640,9 +620,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);
|
||||
}
|
||||
|
@ -650,10 +628,7 @@ todo_wine_if(todo_qualifier)
|
|||
static void test_CoCreateInstance(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
HANDLE thread;
|
||||
DWORD tid, exitcode;
|
||||
IUnknown *pUnk;
|
||||
struct info info;
|
||||
REFCLSID rclsid = &CLSID_InternetZoneManager;
|
||||
|
||||
pUnk = (IUnknown *)0xdeadbeef;
|
||||
|
@ -688,51 +663,15 @@ 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);
|
||||
|
||||
/* show that COM doesn't have to be initialized for multi-threaded apartments if another
|
||||
thread has already done so */
|
||||
|
||||
test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
|
||||
|
||||
info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
|
||||
|
||||
info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
|
||||
|
||||
thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
|
||||
ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
|
||||
|
||||
ok( !WaitForSingleObject(info.wait, 10000 ), "wait timed out\n" );
|
||||
|
||||
test_apt_type(APTTYPE_MTA, APTTYPEQUALIFIER_IMPLICIT_MTA, TRUE, TRUE);
|
||||
|
||||
pUnk = (IUnknown *)0xdeadbeef;
|
||||
hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
|
||||
ok(hr == S_OK, "CoCreateInstance should have returned S_OK instead of 0x%08x\n", hr);
|
||||
if (pUnk) IUnknown_Release(pUnk);
|
||||
|
||||
SetEvent(info.stop);
|
||||
ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
|
||||
|
||||
GetExitCodeThread(thread, &exitcode);
|
||||
hr = exitcode;
|
||||
ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
|
||||
|
||||
CloseHandle(thread);
|
||||
CloseHandle(info.wait);
|
||||
CloseHandle(info.stop);
|
||||
|
||||
test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
|
||||
test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE);
|
||||
}
|
||||
|
||||
static void test_CoGetClassObject(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
HANDLE thread, handle;
|
||||
DWORD tid, exitcode;
|
||||
HANDLE handle;
|
||||
ULONG_PTR cookie;
|
||||
IUnknown *pUnk;
|
||||
struct info info;
|
||||
REFCLSID rclsid = &CLSID_InternetZoneManager;
|
||||
HKEY hkey;
|
||||
LONG res;
|
||||
|
@ -746,46 +685,7 @@ static void test_CoGetClassObject(void)
|
|||
broken(hr == CO_E_NOTINITIALIZED), /* win9x */
|
||||
"CoGetClassObject should have returned E_INVALIDARG instead of 0x%08x\n", hr);
|
||||
|
||||
/* show that COM doesn't have to be initialized for multi-threaded apartments if another
|
||||
thread has already done so */
|
||||
|
||||
test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
|
||||
|
||||
info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
|
||||
|
||||
info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
|
||||
|
||||
thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
|
||||
ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
|
||||
|
||||
ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
|
||||
|
||||
test_apt_type(APTTYPE_MTA, APTTYPEQUALIFIER_IMPLICIT_MTA, TRUE, TRUE);
|
||||
|
||||
pUnk = (IUnknown *)0xdeadbeef;
|
||||
hr = CoGetClassObject(rclsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&pUnk);
|
||||
if(hr == REGDB_E_CLASSNOTREG)
|
||||
skip("IE not installed so can't test CoGetClassObject\n");
|
||||
else
|
||||
{
|
||||
ok(hr == S_OK, "CoGetClassObject should have returned S_OK instead of 0x%08x\n", hr);
|
||||
if (pUnk) IUnknown_Release(pUnk);
|
||||
}
|
||||
|
||||
SetEvent(info.stop);
|
||||
ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
|
||||
|
||||
GetExitCodeThread(thread, &exitcode);
|
||||
hr = exitcode;
|
||||
ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
|
||||
|
||||
CloseHandle(thread);
|
||||
CloseHandle(info.wait);
|
||||
CloseHandle(info.stop);
|
||||
|
||||
test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
|
||||
test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE);
|
||||
|
||||
if (!pRegOverridePredefKey)
|
||||
{
|
||||
|
@ -1886,9 +1786,6 @@ static void test_CoGetObjectContext(void)
|
|||
IObjContext *pObjContext;
|
||||
APTTYPE apttype;
|
||||
THDTYPE thdtype;
|
||||
struct info info;
|
||||
HANDLE thread;
|
||||
DWORD tid, exitcode;
|
||||
GUID id, id2;
|
||||
|
||||
if (!pCoGetObjectContext)
|
||||
|
@ -1901,27 +1798,12 @@ static void test_CoGetObjectContext(void)
|
|||
ok(hr == CO_E_NOTINITIALIZED, "CoGetObjectContext should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
|
||||
ok(pComThreadingInfo == NULL, "pComThreadingInfo should have been set to NULL\n");
|
||||
|
||||
/* show that COM doesn't have to be initialized for multi-threaded apartments if another
|
||||
thread has already done so */
|
||||
pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
|
||||
test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
|
||||
test_apt_type(APTTYPE_MAINSTA, APTTYPEQUALIFIER_NONE);
|
||||
|
||||
info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
|
||||
|
||||
info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
|
||||
|
||||
thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
|
||||
ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
|
||||
|
||||
ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
|
||||
|
||||
test_apt_type(APTTYPE_MTA, APTTYPEQUALIFIER_IMPLICIT_MTA, TRUE, TRUE);
|
||||
|
||||
pComThreadingInfo = NULL;
|
||||
hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
|
||||
ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
|
||||
ok_ole_success(hr, "CoGetObjectContext");
|
||||
|
||||
threadinginfo2 = NULL;
|
||||
hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&threadinginfo2);
|
||||
|
@ -1939,28 +1821,6 @@ static void test_CoGetObjectContext(void)
|
|||
hr = CoGetCurrentLogicalThreadId(&id2);
|
||||
ok(IsEqualGUID(&id, &id2), "got %s, expected %s\n", wine_dbgstr_guid(&id), wine_dbgstr_guid(&id2));
|
||||
|
||||
IComThreadingInfo_Release(pComThreadingInfo);
|
||||
|
||||
SetEvent(info.stop);
|
||||
ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
|
||||
|
||||
GetExitCodeThread(thread, &exitcode);
|
||||
hr = exitcode;
|
||||
ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
|
||||
|
||||
CloseHandle(thread);
|
||||
CloseHandle(info.wait);
|
||||
CloseHandle(info.stop);
|
||||
|
||||
test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
|
||||
|
||||
pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
|
||||
test_apt_type(APTTYPE_MAINSTA, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
|
||||
|
||||
hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
|
||||
ok_ole_success(hr, "CoGetObjectContext");
|
||||
|
||||
hr = IComThreadingInfo_GetCurrentApartmentType(pComThreadingInfo, &apttype);
|
||||
ok_ole_success(hr, "IComThreadingInfo_GetCurrentApartmentType");
|
||||
ok(apttype == APTTYPE_MAINSTA, "apartment type should be APTTYPE_MAINSTA instead of %d\n", apttype);
|
||||
|
@ -2124,9 +1984,6 @@ static void test_CoGetContextToken(void)
|
|||
ULONG refs;
|
||||
ULONG_PTR token, token2;
|
||||
IObjContext *ctx;
|
||||
struct info info;
|
||||
HANDLE thread;
|
||||
DWORD tid, exitcode;
|
||||
|
||||
if (!pCoGetContextToken)
|
||||
{
|
||||
|
@ -2139,49 +1996,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);
|
||||
|
||||
/* show that COM doesn't have to be initialized for multi-threaded apartments if another
|
||||
thread has already done so */
|
||||
|
||||
test_apt_type(APTTYPE_CURRENT, APTTYPEQUALIFIER_NONE, FALSE, FALSE);
|
||||
|
||||
info.wait = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
ok(info.wait != NULL, "CreateEvent failed with error %d\n", GetLastError());
|
||||
|
||||
info.stop = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
ok(info.stop != NULL, "CreateEvent failed with error %d\n", GetLastError());
|
||||
|
||||
thread = CreateThread(NULL, 0, ole_initialize_thread, &info, 0, &tid);
|
||||
ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
|
||||
|
||||
ok( !WaitForSingleObject(info.wait, 10000), "wait timed out\n" );
|
||||
|
||||
test_apt_type(APTTYPE_MTA, APTTYPEQUALIFIER_IMPLICIT_MTA, TRUE, TRUE);
|
||||
|
||||
token = 0;
|
||||
hr = pCoGetContextToken(&token);
|
||||
ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
|
||||
|
||||
token2 = 0;
|
||||
hr = pCoGetContextToken(&token2);
|
||||
ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
|
||||
ok(token == token2, "got different token\n");
|
||||
|
||||
SetEvent(info.stop);
|
||||
ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
|
||||
|
||||
GetExitCodeThread(thread, &exitcode);
|
||||
hr = exitcode;
|
||||
ok(hr == S_OK, "thread should have returned S_OK instead of 0x%08x\n", hr);
|
||||
|
||||
CloseHandle(thread);
|
||||
CloseHandle(info.wait);
|
||||
CloseHandle(info.stop);
|
||||
|
||||
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);
|
||||
|
@ -3185,14 +3004,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)
|
||||
|
@ -3880,6 +3721,71 @@ static void init_funcs(void)
|
|||
pReleaseActCtx = (void*)GetProcAddress(hkernel32, "ReleaseActCtx");
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
hr = CoCreateInstance(&CLSID_InternetZoneManager, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&unk);
|
||||
ok_ole_success(hr, "CoCreateInstance");
|
||||
IUnknown_Release(unk);
|
||||
|
||||
hr = CoGetClassObject(&CLSID_InternetZoneManager, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void **)&unk);
|
||||
ok_ole_success(hr, "CoGetClassObject");
|
||||
IUnknown_Release(unk);
|
||||
|
||||
hr = CoGetObjectContext(&IID_IComThreadingInfo, (void **)&threading_info);
|
||||
ok_ole_success(hr, "CoGetObjectContext");
|
||||
IComThreadingInfo_Release(threading_info);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Some COM functions (perhaps even all of them?) can make use of an "implicit"
|
||||
* multi-threaded apartment created by another thread in the same process. */
|
||||
static void test_implicit_mta(void)
|
||||
{
|
||||
HANDLE thread;
|
||||
|
||||
CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
|
||||
thread = CreateThread(NULL, 0, implicit_mta_proc, NULL, 0, NULL);
|
||||
ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
|
||||
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
START_TEST(compobj)
|
||||
{
|
||||
init_funcs();
|
||||
|
@ -3929,4 +3835,5 @@ START_TEST(compobj)
|
|||
test_IInitializeSpy();
|
||||
test_CoGetInstanceFromFile();
|
||||
test_GlobalOptions();
|
||||
test_implicit_mta();
|
||||
}
|
||||
|
|
|
@ -34,10 +34,37 @@
|
|||
#include "initguid.h"
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "wine/heap.h"
|
||||
|
||||
#define DEFINE_EXPECT(func) \
|
||||
static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
|
||||
|
||||
#define SET_EXPECT(func) \
|
||||
expect_ ## func = TRUE
|
||||
|
||||
#define CHECK_EXPECT2(func) \
|
||||
do { \
|
||||
ok(expect_ ##func, "unexpected call " #func "\n"); \
|
||||
called_ ## func = TRUE; \
|
||||
}while(0)
|
||||
|
||||
#define CHECK_EXPECT(func) \
|
||||
do { \
|
||||
CHECK_EXPECT2(func); \
|
||||
expect_ ## func = FALSE; \
|
||||
}while(0)
|
||||
|
||||
#define CHECK_CALLED(func) \
|
||||
do { \
|
||||
ok(called_ ## func, "expected " #func "\n"); \
|
||||
expect_ ## func = called_ ## func = FALSE; \
|
||||
}while(0)
|
||||
|
||||
DEFINE_GUID(CLSID_StdGlobalInterfaceTable,0x00000323,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
|
||||
DEFINE_GUID(CLSID_ManualResetEvent, 0x0000032c,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
|
||||
|
||||
static const GUID CLSID_WineTestPSFactoryBuffer = { 0x22222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
|
||||
|
||||
/* functions that are not present on all versions of Windows */
|
||||
static HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit);
|
||||
static HRESULT (WINAPI *pDllGetClassObject)(REFCLSID,REFIID,LPVOID);
|
||||
|
@ -281,6 +308,253 @@ static const IClassFactoryVtbl TestClassFactory_Vtbl =
|
|||
|
||||
static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl };
|
||||
|
||||
DEFINE_EXPECT(Invoke);
|
||||
DEFINE_EXPECT(CreateStub);
|
||||
DEFINE_EXPECT(CreateProxy);
|
||||
DEFINE_EXPECT(GetWindow);
|
||||
DEFINE_EXPECT(Disconnect);
|
||||
|
||||
static HRESULT WINAPI OleWindow_QueryInterface(IOleWindow *iface, REFIID riid, void **ppv)
|
||||
{
|
||||
ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid));
|
||||
*ppv = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
static ULONG WINAPI OleWindow_AddRef(IOleWindow *iface)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
static ULONG WINAPI OleWindow_Release(IOleWindow *iface)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI OleWindow_GetWindow(IOleWindow *iface, HWND *hwnd)
|
||||
{
|
||||
CHECK_EXPECT(GetWindow);
|
||||
*hwnd = (HWND)0xdeadbeef;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const IOleWindowVtbl OleWindowVtbl = {
|
||||
OleWindow_QueryInterface,
|
||||
OleWindow_AddRef,
|
||||
OleWindow_Release,
|
||||
OleWindow_GetWindow,
|
||||
/* not needed */
|
||||
};
|
||||
|
||||
static IOleWindow Test_OleWindow = { &OleWindowVtbl };
|
||||
|
||||
static HRESULT WINAPI OleClientSite_QueryInterface(IOleClientSite *iface, REFIID riid, void **ppv)
|
||||
{
|
||||
if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IOleClientSite))
|
||||
*ppv = iface;
|
||||
else if (IsEqualGUID(riid, &IID_IOleWindow))
|
||||
*ppv = &Test_OleWindow;
|
||||
else
|
||||
{
|
||||
*ppv = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
IUnknown_AddRef((IUnknown*)*ppv);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static ULONG WINAPI OleClientSite_AddRef(IOleClientSite *iface)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
static ULONG WINAPI OleClientSite_Release(IOleClientSite *iface)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const IOleClientSiteVtbl OleClientSiteVtbl = {
|
||||
OleClientSite_QueryInterface,
|
||||
OleClientSite_AddRef,
|
||||
OleClientSite_Release,
|
||||
/* we don't need the rest, we never call it */
|
||||
};
|
||||
|
||||
static IOleClientSite Test_OleClientSite = { &OleClientSiteVtbl };
|
||||
|
||||
typedef struct {
|
||||
IRpcStubBuffer IRpcStubBuffer_iface;
|
||||
LONG ref;
|
||||
IRpcStubBuffer *buffer;
|
||||
} StubBufferWrapper;
|
||||
|
||||
static StubBufferWrapper *impl_from_IRpcStubBuffer(IRpcStubBuffer *iface)
|
||||
{
|
||||
return CONTAINING_RECORD(iface, StubBufferWrapper, IRpcStubBuffer_iface);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI RpcStubBuffer_QueryInterface(IRpcStubBuffer *iface, REFIID riid, void **ppv)
|
||||
{
|
||||
StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
|
||||
|
||||
if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IRpcStubBuffer, riid)) {
|
||||
*ppv = &This->IRpcStubBuffer_iface;
|
||||
}else {
|
||||
*ppv = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
IUnknown_AddRef((IUnknown*)*ppv);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static ULONG WINAPI RpcStubBuffer_AddRef(IRpcStubBuffer *iface)
|
||||
{
|
||||
StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
|
||||
return InterlockedIncrement(&This->ref);
|
||||
}
|
||||
|
||||
static ULONG WINAPI RpcStubBuffer_Release(IRpcStubBuffer *iface)
|
||||
{
|
||||
StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
|
||||
LONG ref = InterlockedDecrement(&This->ref);
|
||||
if(!ref) {
|
||||
IRpcStubBuffer_Release(This->buffer);
|
||||
heap_free(This);
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI RpcStubBuffer_Connect(IRpcStubBuffer *iface, IUnknown *pUnkServer)
|
||||
{
|
||||
ok(0, "unexpected call\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static void WINAPI RpcStubBuffer_Disconnect(IRpcStubBuffer *iface)
|
||||
{
|
||||
CHECK_EXPECT(Disconnect);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI RpcStubBuffer_Invoke(IRpcStubBuffer *iface, RPCOLEMESSAGE *_prpcmsg,
|
||||
IRpcChannelBuffer *_pRpcChannelBuffer)
|
||||
{
|
||||
StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
|
||||
void *dest_context_data;
|
||||
DWORD dest_context;
|
||||
HRESULT hr;
|
||||
|
||||
CHECK_EXPECT(Invoke);
|
||||
|
||||
hr = IRpcChannelBuffer_GetDestCtx(_pRpcChannelBuffer, &dest_context, &dest_context_data);
|
||||
ok(hr == S_OK, "GetDestCtx failed: %08x\n", hr);
|
||||
ok(dest_context == MSHCTX_INPROC, "desc_context = %x\n", dest_context);
|
||||
ok(!dest_context_data, "desc_context_data = %p\n", dest_context_data);
|
||||
|
||||
return IRpcStubBuffer_Invoke(This->buffer, _prpcmsg, _pRpcChannelBuffer);
|
||||
}
|
||||
|
||||
static IRpcStubBuffer *WINAPI RpcStubBuffer_IsIIDSupported(IRpcStubBuffer *iface, REFIID riid)
|
||||
{
|
||||
ok(0, "unexpected call\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ULONG WINAPI RpcStubBuffer_CountRefs(IRpcStubBuffer *iface)
|
||||
{
|
||||
ok(0, "unexpected call\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI RpcStubBuffer_DebugServerQueryInterface(IRpcStubBuffer *iface, void **ppv)
|
||||
{
|
||||
ok(0, "unexpected call\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static void WINAPI RpcStubBuffer_DebugServerRelease(IRpcStubBuffer *iface, void *pv)
|
||||
{
|
||||
ok(0, "unexpected call\n");
|
||||
}
|
||||
|
||||
static const IRpcStubBufferVtbl RpcStubBufferVtbl = {
|
||||
RpcStubBuffer_QueryInterface,
|
||||
RpcStubBuffer_AddRef,
|
||||
RpcStubBuffer_Release,
|
||||
RpcStubBuffer_Connect,
|
||||
RpcStubBuffer_Disconnect,
|
||||
RpcStubBuffer_Invoke,
|
||||
RpcStubBuffer_IsIIDSupported,
|
||||
RpcStubBuffer_CountRefs,
|
||||
RpcStubBuffer_DebugServerQueryInterface,
|
||||
RpcStubBuffer_DebugServerRelease
|
||||
};
|
||||
|
||||
static IPSFactoryBuffer *ps_factory_buffer;
|
||||
|
||||
static HRESULT WINAPI PSFactoryBuffer_QueryInterface(IPSFactoryBuffer *iface, REFIID riid, void **ppv)
|
||||
{
|
||||
if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPSFactoryBuffer))
|
||||
*ppv = iface;
|
||||
else
|
||||
{
|
||||
*ppv = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
IUnknown_AddRef((IUnknown*)*ppv);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static ULONG WINAPI PSFactoryBuffer_AddRef(IPSFactoryBuffer *iface)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
static ULONG WINAPI PSFactoryBuffer_Release(IPSFactoryBuffer *iface)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI PSFactoryBuffer_CreateProxy(IPSFactoryBuffer *iface, IUnknown *outer,
|
||||
REFIID riid, IRpcProxyBuffer **ppProxy, void **ppv)
|
||||
{
|
||||
CHECK_EXPECT(CreateProxy);
|
||||
return IPSFactoryBuffer_CreateProxy(ps_factory_buffer, outer, riid, ppProxy, ppv);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI PSFactoryBuffer_CreateStub(IPSFactoryBuffer *iface, REFIID riid,
|
||||
IUnknown *server, IRpcStubBuffer **ppStub)
|
||||
{
|
||||
StubBufferWrapper *stub;
|
||||
HRESULT hr;
|
||||
|
||||
CHECK_EXPECT(CreateStub);
|
||||
|
||||
ok(server == (IUnknown*)&Test_OleClientSite, "unexpected server %p\n", server);
|
||||
|
||||
stub = heap_alloc(sizeof(*stub));
|
||||
stub->IRpcStubBuffer_iface.lpVtbl = &RpcStubBufferVtbl;
|
||||
stub->ref = 1;
|
||||
|
||||
hr = IPSFactoryBuffer_CreateStub(ps_factory_buffer, riid, server, &stub->buffer);
|
||||
ok(hr == S_OK, "CreateStub failed: %08x\n", hr);
|
||||
|
||||
*ppStub = &stub->IRpcStubBuffer_iface;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static IPSFactoryBufferVtbl PSFactoryBufferVtbl =
|
||||
{
|
||||
PSFactoryBuffer_QueryInterface,
|
||||
PSFactoryBuffer_AddRef,
|
||||
PSFactoryBuffer_Release,
|
||||
PSFactoryBuffer_CreateProxy,
|
||||
PSFactoryBuffer_CreateStub
|
||||
};
|
||||
|
||||
static IPSFactoryBuffer PSFactoryBuffer = { &PSFactoryBufferVtbl };
|
||||
|
||||
#define RELEASEMARSHALDATA WM_USER
|
||||
|
||||
struct host_object_data
|
||||
|
@ -289,18 +563,31 @@ struct host_object_data
|
|||
IID iid;
|
||||
IUnknown *object;
|
||||
MSHLFLAGS marshal_flags;
|
||||
HANDLE marshal_event;
|
||||
IMessageFilter *filter;
|
||||
IUnknown *register_object;
|
||||
CLSID register_clsid;
|
||||
HANDLE marshal_event;
|
||||
};
|
||||
|
||||
#ifndef __REACTOS__ /* FIXME: Inspect */
|
||||
static IPSFactoryBuffer PSFactoryBuffer;
|
||||
#endif
|
||||
|
||||
static DWORD CALLBACK host_object_proc(LPVOID p)
|
||||
{
|
||||
struct host_object_data *data = p;
|
||||
DWORD registration_key;
|
||||
HRESULT hr;
|
||||
MSG msg;
|
||||
|
||||
pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
|
||||
if(data->register_object) {
|
||||
hr = CoRegisterClassObject(&data->register_clsid, data->register_object,
|
||||
CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®istration_key);
|
||||
ok(hr == S_OK, "CoRegisterClassObject failed: %08x\n", hr);
|
||||
}
|
||||
|
||||
if (data->filter)
|
||||
{
|
||||
IMessageFilter * prev_filter = NULL;
|
||||
|
@ -335,31 +622,27 @@ static DWORD CALLBACK host_object_proc(LPVOID p)
|
|||
return hr;
|
||||
}
|
||||
|
||||
static DWORD start_host_object2(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, IMessageFilter *filter, HANDLE *thread)
|
||||
static DWORD start_host_object2(struct host_object_data *object_data, HANDLE *thread)
|
||||
{
|
||||
DWORD tid = 0;
|
||||
HANDLE marshal_event = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||
struct host_object_data *data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
|
||||
|
||||
data->stream = stream;
|
||||
data->iid = *riid;
|
||||
data->object = object;
|
||||
data->marshal_flags = marshal_flags;
|
||||
data->marshal_event = marshal_event;
|
||||
data->filter = filter;
|
||||
struct host_object_data *data;
|
||||
|
||||
data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
|
||||
*data = *object_data;
|
||||
data->marshal_event = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||
*thread = CreateThread(NULL, 0, host_object_proc, data, 0, &tid);
|
||||
|
||||
/* wait for marshaling to complete before returning */
|
||||
ok( !WaitForSingleObject(marshal_event, 10000), "wait timed out\n" );
|
||||
CloseHandle(marshal_event);
|
||||
ok( !WaitForSingleObject(data->marshal_event, 10000), "wait timed out\n" );
|
||||
CloseHandle(data->marshal_event);
|
||||
|
||||
return tid;
|
||||
}
|
||||
|
||||
static DWORD start_host_object(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, HANDLE *thread)
|
||||
{
|
||||
return start_host_object2(stream, riid, object, marshal_flags, NULL, thread);
|
||||
struct host_object_data object_data = { stream, *riid, object, marshal_flags };
|
||||
return start_host_object2(&object_data, thread);
|
||||
}
|
||||
|
||||
/* asks thread to release the marshal data because it has to be done by the
|
||||
|
@ -962,6 +1245,75 @@ static void test_marshal_proxy_mta_apartment_shutdown(void)
|
|||
pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
}
|
||||
|
||||
static void test_marshal_channel_buffer(void)
|
||||
{
|
||||
DWORD registration_key;
|
||||
IUnknown *proxy = NULL;
|
||||
IOleWindow *ole_window;
|
||||
HWND hwnd;
|
||||
CLSID clsid;
|
||||
DWORD tid;
|
||||
HANDLE thread;
|
||||
HRESULT hr;
|
||||
|
||||
struct host_object_data object_data = { NULL, IID_IOleClientSite, (IUnknown*)&Test_OleClientSite,
|
||||
MSHLFLAGS_NORMAL, NULL, (IUnknown*)&PSFactoryBuffer,
|
||||
CLSID_WineTestPSFactoryBuffer };
|
||||
|
||||
cLocks = 0;
|
||||
external_connections = 0;
|
||||
|
||||
hr = CoGetPSClsid(&IID_IOleWindow, &clsid);
|
||||
ok_ole_success(hr, "CoGetPSClsid");
|
||||
|
||||
hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer,
|
||||
(void **)&ps_factory_buffer);
|
||||
ok_ole_success(hr, "CoGetClassObject");
|
||||
|
||||
hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream);
|
||||
ok_ole_success(hr, CreateStreamOnHGlobal);
|
||||
tid = start_host_object2(&object_data, &thread);
|
||||
|
||||
IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL);
|
||||
hr = CoUnmarshalInterface(object_data.stream, &IID_IUnknown, (void **)&proxy);
|
||||
ok_ole_success(hr, CoUnmarshalInterface);
|
||||
IStream_Release(object_data.stream);
|
||||
|
||||
hr = CoRegisterClassObject(&CLSID_WineTestPSFactoryBuffer, (IUnknown *)&PSFactoryBuffer,
|
||||
CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®istration_key);
|
||||
ok(hr == S_OK, "CoRegisterClassObject failed: %08x\n", hr);
|
||||
|
||||
hr = CoRegisterPSClsid(&IID_IOleWindow, &CLSID_WineTestPSFactoryBuffer);
|
||||
ok(hr == S_OK, "CoRegisterPSClsid failed: %08x\n", hr);
|
||||
|
||||
SET_EXPECT(CreateStub);
|
||||
SET_EXPECT(CreateProxy);
|
||||
hr = IUnknown_QueryInterface(proxy, &IID_IOleWindow, (void**)&ole_window);
|
||||
ok(hr == S_OK, "Could not get IOleWindow iface: %08x\n", hr);
|
||||
CHECK_CALLED(CreateStub);
|
||||
CHECK_CALLED(CreateProxy);
|
||||
|
||||
SET_EXPECT(Invoke);
|
||||
SET_EXPECT(GetWindow);
|
||||
hr = IOleWindow_GetWindow(ole_window, &hwnd);
|
||||
ok(hr == S_OK, "GetWindow failed: %08x\n", hr);
|
||||
ok(hwnd == (HWND)0xdeadbeef, "hwnd = %p\n", hwnd);
|
||||
CHECK_CALLED(Invoke);
|
||||
CHECK_CALLED(GetWindow);
|
||||
|
||||
IOleWindow_Release(ole_window);
|
||||
|
||||
SET_EXPECT(Disconnect);
|
||||
IUnknown_Release(proxy);
|
||||
todo_wine
|
||||
CHECK_CALLED(Disconnect);
|
||||
|
||||
hr = CoRevokeClassObject(registration_key);
|
||||
ok(hr == S_OK, "CoRevokeClassObject failed: %08x\n", hr);
|
||||
|
||||
end_host_object(tid, thread);
|
||||
}
|
||||
|
||||
struct ncu_params
|
||||
{
|
||||
LPSTREAM stream;
|
||||
|
@ -1965,25 +2317,27 @@ static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
|
|||
static void test_message_filter(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
IStream *pStream = NULL;
|
||||
IClassFactory *cf = NULL;
|
||||
DWORD tid;
|
||||
IUnknown *proxy = NULL;
|
||||
IMessageFilter *prev_filter = NULL;
|
||||
HANDLE thread;
|
||||
|
||||
struct host_object_data object_data = { NULL, IID_IClassFactory, (IUnknown*)&Test_ClassFactory,
|
||||
MSHLFLAGS_NORMAL, &MessageFilter };
|
||||
|
||||
cLocks = 0;
|
||||
|
||||
hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
|
||||
hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream);
|
||||
ok_ole_success(hr, CreateStreamOnHGlobal);
|
||||
tid = start_host_object2(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &MessageFilter, &thread);
|
||||
tid = start_host_object2(&object_data, &thread);
|
||||
|
||||
ok_more_than_one_lock();
|
||||
|
||||
IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
|
||||
hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&cf);
|
||||
IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL);
|
||||
hr = CoUnmarshalInterface(object_data.stream, &IID_IClassFactory, (void **)&cf);
|
||||
ok_ole_success(hr, CoUnmarshalInterface);
|
||||
IStream_Release(pStream);
|
||||
IStream_Release(object_data.stream);
|
||||
|
||||
ok_more_than_one_lock();
|
||||
|
||||
|
@ -3419,6 +3773,169 @@ 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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
/* 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();
|
||||
}
|
||||
|
||||
static const char *debugstr_iid(REFIID riid)
|
||||
{
|
||||
static char name[256];
|
||||
|
@ -3692,13 +4209,15 @@ static IChannelHook TestChannelHook = { &TestChannelHookVtbl };
|
|||
|
||||
static void test_channel_hook(void)
|
||||
{
|
||||
IStream *pStream = NULL;
|
||||
IClassFactory *cf = NULL;
|
||||
DWORD tid;
|
||||
IUnknown *proxy = NULL;
|
||||
HANDLE thread;
|
||||
HRESULT hr;
|
||||
|
||||
struct host_object_data object_data = { NULL, IID_IClassFactory, (IUnknown*)&Test_ClassFactory,
|
||||
MSHLFLAGS_NORMAL, &MessageFilter };
|
||||
|
||||
hr = CoRegisterChannelHook(&EXTENTID_WineTest, &TestChannelHook);
|
||||
ok_ole_success(hr, CoRegisterChannelHook);
|
||||
|
||||
|
@ -3707,17 +4226,17 @@ static void test_channel_hook(void)
|
|||
|
||||
cLocks = 0;
|
||||
|
||||
hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
|
||||
hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream);
|
||||
ok_ole_success(hr, CreateStreamOnHGlobal);
|
||||
tid = start_host_object2(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &MessageFilter, &thread);
|
||||
tid = start_host_object2(&object_data, &thread);
|
||||
server_tid = tid;
|
||||
|
||||
ok_more_than_one_lock();
|
||||
|
||||
IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
|
||||
hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&cf);
|
||||
IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL);
|
||||
hr = CoUnmarshalInterface(object_data.stream, &IID_IClassFactory, (void **)&cf);
|
||||
ok_ole_success(hr, CoUnmarshalInterface);
|
||||
IStream_Release(pStream);
|
||||
IStream_Release(object_data.stream);
|
||||
|
||||
ok_more_than_one_lock();
|
||||
|
||||
|
@ -3765,6 +4284,7 @@ START_TEST(marshal)
|
|||
register_test_window();
|
||||
|
||||
test_cocreateinstance_proxy();
|
||||
test_implicit_mta();
|
||||
|
||||
pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
|
||||
|
@ -3802,6 +4322,7 @@ START_TEST(marshal)
|
|||
with_external_conn = !with_external_conn;
|
||||
} while (with_external_conn);
|
||||
|
||||
test_marshal_channel_buffer();
|
||||
test_hresult_marshaling();
|
||||
test_proxy_used_in_wrong_thread();
|
||||
test_message_filter();
|
||||
|
|
|
@ -4082,6 +4082,83 @@ static void check_storage_contents(IStorage *stg, const struct storage_def *stg_
|
|||
}
|
||||
}
|
||||
|
||||
static HRESULT stgmedium_cmp(const STGMEDIUM *med1, STGMEDIUM *med2)
|
||||
{
|
||||
BYTE *data1, *data2;
|
||||
ULONG datasize1, datasize2;
|
||||
|
||||
if (med1->tymed != med2->tymed)
|
||||
return E_FAIL;
|
||||
|
||||
if (med1->tymed == TYMED_MFPICT)
|
||||
{
|
||||
METAFILEPICT *mfpict1 = GlobalLock(U(med1)->hMetaFilePict);
|
||||
METAFILEPICT *mfpict2 = GlobalLock(U(med2)->hMetaFilePict);
|
||||
|
||||
datasize1 = GetMetaFileBitsEx(mfpict1->hMF, 0, NULL);
|
||||
datasize2 = GetMetaFileBitsEx(mfpict2->hMF, 0, NULL);
|
||||
if (datasize1 == datasize2)
|
||||
{
|
||||
data1 = HeapAlloc(GetProcessHeap(), 0, datasize1);
|
||||
data2 = HeapAlloc(GetProcessHeap(), 0, datasize2);
|
||||
GetMetaFileBitsEx(mfpict1->hMF, datasize1, data1);
|
||||
GetMetaFileBitsEx(mfpict2->hMF, datasize2, data2);
|
||||
}
|
||||
else return E_FAIL;
|
||||
}
|
||||
else if (med1->tymed == TYMED_ENHMF)
|
||||
{
|
||||
datasize1 = GetEnhMetaFileBits(med1->hEnhMetaFile, 0, NULL);
|
||||
datasize2 = GetEnhMetaFileBits(med2->hEnhMetaFile, 0, NULL);
|
||||
if (datasize1 == datasize2)
|
||||
{
|
||||
data1 = HeapAlloc(GetProcessHeap(), 0, datasize1);
|
||||
data2 = HeapAlloc(GetProcessHeap(), 0, datasize2);
|
||||
GetEnhMetaFileBits(med1->hEnhMetaFile, datasize1, data1);
|
||||
GetEnhMetaFileBits(med2->hEnhMetaFile, datasize2, data2);
|
||||
}
|
||||
else return E_FAIL;
|
||||
}
|
||||
else if (med1->tymed == TYMED_HGLOBAL)
|
||||
{
|
||||
datasize1 = GlobalSize(med1->hGlobal);
|
||||
datasize2 = GlobalSize(med2->hGlobal);
|
||||
|
||||
if (datasize1 == datasize2)
|
||||
{
|
||||
data1 = GlobalLock(med1->hGlobal);
|
||||
data2 = GlobalLock(med2->hGlobal);
|
||||
}
|
||||
else
|
||||
return E_FAIL;
|
||||
}
|
||||
else
|
||||
return E_NOTIMPL;
|
||||
|
||||
if (memcmp(data1, data2, datasize1) != 0)
|
||||
return E_FAIL;
|
||||
|
||||
if (med1->tymed == TYMED_HGLOBAL)
|
||||
{
|
||||
GlobalUnlock(U(med1)->hGlobal);
|
||||
GlobalUnlock(U(med2)->hGlobal);
|
||||
}
|
||||
else if (med1->tymed == TYMED_MFPICT)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, data1);
|
||||
HeapFree(GetProcessHeap(), 0, data2);
|
||||
GlobalUnlock(U(med1)->hMetaFilePict);
|
||||
GlobalUnlock(U(med2)->hMetaFilePict);
|
||||
}
|
||||
else
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, data1);
|
||||
HeapFree(GetProcessHeap(), 0, data2);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static IStorage *create_storage_from_def(const struct storage_def *stg_def)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
@ -4254,8 +4331,10 @@ static void test_data_cache_save_data(void)
|
|||
IStorage *doc;
|
||||
IOleCache2 *cache;
|
||||
IPersistStorage *persist;
|
||||
IDataObject *odata;
|
||||
int enumerated_streams, matched_streams, i;
|
||||
DWORD dummy;
|
||||
STGMEDIUM stgmeds[MAX_FMTS];
|
||||
struct tests_data_cache
|
||||
{
|
||||
FORMATETC fmts[MAX_FMTS];
|
||||
|
@ -4370,9 +4449,9 @@ static void test_data_cache_save_data(void)
|
|||
ok(SUCCEEDED(hr), "unexpected %#x\n", hr);
|
||||
if (i < pdata->num_set)
|
||||
{
|
||||
get_stgmedium(pdata->fmts[i].cfFormat, &stgmed);
|
||||
get_stgdef(&pdata->stg_def, pdata->fmts[i].cfFormat, &stgmed, i);
|
||||
hr = IOleCache2_SetData(cache, &pdata->fmts[i], &stgmed, TRUE);
|
||||
get_stgmedium(pdata->fmts[i].cfFormat, &stgmeds[i]);
|
||||
get_stgdef(&pdata->stg_def, pdata->fmts[i].cfFormat, &stgmeds[i], i);
|
||||
hr = IOleCache2_SetData(cache, &pdata->fmts[i], &stgmeds[i], FALSE);
|
||||
ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
}
|
||||
}
|
||||
|
@ -4403,12 +4482,41 @@ static void test_data_cache_save_data(void)
|
|||
ok(enumerated_streams == pdata->stg_def.stream_count, "created %d != def streams %d\n",
|
||||
enumerated_streams, pdata->stg_def.stream_count);
|
||||
|
||||
for (i = 0; i < pdata->num_set; i++)
|
||||
HeapFree(GetProcessHeap(), 0, (void *)pdata->stg_def.stream[i].data);
|
||||
IPersistStorage_Release(persist);
|
||||
IOleCache2_Release(cache);
|
||||
|
||||
/* now test _Load/_GetData using the storage we used for _Save */
|
||||
hr = CreateDataCache(NULL, pdata->clsid, &IID_IOleCache2, (void **)&cache);
|
||||
ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
hr = IOleCache2_QueryInterface(cache, &IID_IPersistStorage, (void **)&persist);
|
||||
ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
|
||||
hr = IStorage_SetClass(doc, pdata->clsid);
|
||||
ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
trace("IPersistStorage_Load\n");
|
||||
hr = IPersistStorage_Load(persist, doc);
|
||||
ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
|
||||
hr = IOleCache2_QueryInterface(cache, &IID_IDataObject, (void **)&odata);
|
||||
ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
for (i = 0; i < pdata->num_set; i++)
|
||||
{
|
||||
hr = IDataObject_GetData(odata, &pdata->fmts[i], &stgmed);
|
||||
ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
|
||||
hr = stgmedium_cmp(&stgmeds[i], &stgmed);
|
||||
ok(hr == S_OK, "unexpected %#x\n", hr);
|
||||
ReleaseStgMedium(&stgmed);
|
||||
ReleaseStgMedium(&stgmeds[i]);
|
||||
}
|
||||
|
||||
IDataObject_Release(odata);
|
||||
IPersistStorage_Release(persist);
|
||||
IStorage_Release(doc);
|
||||
IOleCache2_Release(cache);
|
||||
for (i = 0; i < pdata->num_set; i++)
|
||||
HeapFree(GetProcessHeap(), 0, (void *)pdata->stg_def.stream[i].data);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue