[OLE32_WINETEST] Sync with Wine Staging 3.9. CORE-14656

This commit is contained in:
Amine Khaldi 2018-06-04 03:46:11 +01:00
parent 85037eb745
commit a6cdf4ff08
3 changed files with 760 additions and 224 deletions

View file

@ -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();
}

View file

@ -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, &registration_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, &registration_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();

View file

@ -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);
}
}