This patch reworks the structure of the tests for OLE's default object
handler. We want, at least, to:
- Test its behaviour when object is not running.
- Test its behaviour when is being aggregated by a custom handler.
- Test that it delegates appropriately to datacache.
- Test that it delegates appropriately to running object.
The present patch adds a local server (EXE), ands tests that some calls
in some interfaces are delegated to it after calling _Run on the
IRunnableObject interface.
Signed-off-by: Sergio Gómez Del Real <sdelreal(a)codeweavers.com>
---
dlls/ole32/tests/defaulthandler.c | 681 +++++++++++++++++++++++++++++---------
1 file changed, 528 insertions(+), 153 deletions(-)
diff --git a/dlls/ole32/tests/defaulthandler.c b/dlls/ole32/tests/defaulthandler.c
index 60bc29c08d..6ee44d6320 100644
--- a/dlls/ole32/tests/defaulthandler.c
+++ b/dlls/ole32/tests/defaulthandler.c
@@ -60,112 +60,390 @@
expect_ ## func = called_ ## func = FALSE; \
}while(0)
+#define CHARS_IN_GUID 39
+#define CLSID_KEY_LEN (CHARS_IN_GUID+6)
+
DEFINE_EXPECT(CF_QueryInterface_ClassFactory);
-DEFINE_EXPECT(CF_CreateInstance);
-DEFINE_EXPECT(CF_QueryInterface_IMarshal);
+DEFINE_EXPECT(OleObject_Update);
+DEFINE_EXPECT(PStorage_InitNew);
-static HRESULT create_storage(IStorage **stg)
+struct TestClass
{
- HRESULT hr;
- ILockBytes *lock_bytes;
-
- hr = CreateILockBytesOnHGlobal(NULL, TRUE, &lock_bytes);
- if(SUCCEEDED(hr))
- {
- hr = StgCreateDocfileOnILockBytes(lock_bytes,
- STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, stg);
- ILockBytes_Release(lock_bytes);
- }
- return hr;
-}
-
-typedef struct
-{
- DWORD version;
- DWORD flags;
- DWORD link_update_opt;
- DWORD res;
- DWORD moniker_size;
-} ole_stream_header_t;
-
-static void test_olestream(void)
-{
- HRESULT hr;
- const CLSID non_existent_class = {0xa5f1772f, 0x3772, 0x490f, {0x9e, 0xc6, 0x77, 0x13, 0xe8, 0xb3, 0x4b, 0x5d}};
- IOleObject *ole_obj;
- IPersistStorage *persist;
- IStorage *stg;
- IStream *stm;
- static const WCHAR olestream[] = {1,'O','l','e',0};
- ULONG read;
- ole_stream_header_t header;
-
- hr = create_storage(&stg);
- ok(hr == S_OK, "got %08x\n", hr);
-
- hr = IStorage_OpenStream(stg, olestream, NULL, STGM_SHARE_EXCLUSIVE | STGM_READ, 0, &stm);
- ok(hr == STG_E_FILENOTFOUND, "got %08x\n", hr);
-
- hr = OleCreateDefaultHandler(&non_existent_class, 0, &IID_IOleObject, (void**)&ole_obj);
- ok(hr == S_OK, "got %08x\n", hr);
-
- hr = IOleObject_QueryInterface(ole_obj, &IID_IPersistStorage, (void**)&persist);
- ok(hr == S_OK, "got %08x\n", hr);
-
- hr = IPersistStorage_InitNew(persist, stg);
- ok(hr == S_OK, "got %08x\n", hr);
-
- hr = IStorage_OpenStream(stg, olestream, NULL, STGM_SHARE_EXCLUSIVE | STGM_READ, 0, &stm);
- ok(hr == S_OK, "got %08x\n", hr);
- hr = IStream_Read(stm, &header, sizeof(header), &read);
- ok(hr == S_OK, "got %08x\n", hr);
- ok(read == sizeof(header), "read %d\n", read);
- ok(header.version == 0x02000001, "got version %08x\n", header.version);
- ok(header.flags == 0x0, "got flags %08x\n", header.flags);
- ok(header.link_update_opt == 0x0, "got link update option %08x\n", header.link_update_opt);
- ok(header.res == 0x0, "got reserved %08x\n", header.res);
- ok(header.moniker_size == 0x0, "got moniker size %08x\n", header.moniker_size);
-
- IStream_Release(stm);
-
- IPersistStorage_Release(persist);
- IOleObject_Release(ole_obj);
-
- IStorage_Release(stg);
-}
-
-static HRESULT WINAPI test_class_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
+ IUnknown IUnknown_iface;
+ IOleObject IOleObject_iface;
+ IDataObject IDataObject_iface;
+ IPersistStorage IPersistStorage_iface;
+
+ LONG ref;
+ CLSID clsid;
+};
+typedef struct TestClass TestClass;
+
+const CLSID CLSID_Test_Server = {0x0f77e570,0x80c3,0x11e2,{0x9e,0x96,0x08,0x00,0x20,0x0c,0x9a,0x66}};
+static WCHAR clsid_key[CLSID_KEY_LEN] = {'C','L','S','I','D','\\',0};
+static int wine_argc;
+static char **wine_argv;
+static IUnknown *dfhandler_unk;
+static TestClass *test_class;
+
+static HRESULT WINAPI TC_IUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
{
- if(IsEqualGUID(riid, &IID_IUnknown)) {
+ if (IsEqualGUID(riid, &IID_IUnknown))
*ppv = iface;
- return S_OK;
- }else if(IsEqualGUID(riid, &IID_IOleObject)) {
- ok(0, "unexpected query for IOleObject interface\n");
+ else if (IsEqualGUID(riid, &IID_IOleObject))
+ *ppv = &test_class->IOleObject_iface;
+ else if (IsEqualGUID(riid, &IID_IDataObject))
+ *ppv = &test_class->IDataObject_iface;
+ else if (IsEqualGUID(riid, &IID_IPersistStorage))
+ *ppv = &test_class->IPersistStorage_iface;
+ else {
*ppv = NULL;
return E_NOINTERFACE;
}
- *ppv = NULL;
- return E_NOINTERFACE;
+ IUnknown_AddRef((IUnknown *)*ppv);
+ return S_OK;
}
-static ULONG WINAPI test_class_AddRef(IUnknown *iface)
+static ULONG WINAPI TC_IUnknown_AddRef(IUnknown *iface)
{
- return 2;
+ return InterlockedIncrement(&test_class->ref);
}
-static ULONG WINAPI test_class_Release(IUnknown *iface)
+static ULONG WINAPI TC_IUnknown_Release(IUnknown *iface)
{
- return 1;
+ return InterlockedDecrement(&test_class->ref);
}
-static const IUnknownVtbl test_class_vtbl = {
- test_class_QueryInterface,
- test_class_AddRef,
- test_class_Release,
+static const IUnknownVtbl TC_IUnknown_Vtbl = {
+ TC_IUnknown_QueryInterface,
+ TC_IUnknown_AddRef,
+ TC_IUnknown_Release,
};
-static IUnknown test_class = { &test_class_vtbl };
+static HRESULT WINAPI TC_IOleObject_QueryInterface(IOleObject *iface, REFIID riid, void **ppv)
+{
+ return IUnknown_QueryInterface(&test_class->IUnknown_iface, riid, ppv);
+}
+
+static ULONG WINAPI TC_IOleObject_AddRef(IOleObject *iface)
+{
+ return IUnknown_AddRef(&test_class->IUnknown_iface);
+}
+
+static ULONG WINAPI TC_IOleObject_Release(IOleObject *iface)
+{
+ return IUnknown_Release(&test_class->IUnknown_iface);
+}
+
+static HRESULT WINAPI TC_IOleObject_Advise(IOleObject *iface, IAdviseSink *advs, DWORD *conn)
+{
+ return S_OK;
+}
+
+static HRESULT WINAPI TC_IOleObject_Close(IOleObject *iface, DWORD save_opt)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IOleObject_DoVerb(IOleObject *iface, LONG verb,
+ LPMSG msg, IOleClientSite *actv, LONG lindex, HWND hwnd, LPCRECT pos_rec)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IOleObject_EnumAdvise(IOleObject *iface, IEnumSTATDATA **stat)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IOleObject_EnumVerbs(IOleObject *iface, IEnumOLEVERB **enumole)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IOleObject_GetClientSite(IOleObject *iface, IOleClientSite **csite)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IOleObject_GetClipboardData(IOleObject *iface,
+ DWORD res, IDataObject **dobj)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IOleObject_GetExtent(IOleObject *iface, DWORD draw_asp, SIZEL *size)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IOleObject_GetMiscStatus(IOleObject *iface, DWORD asp, DWORD *stat)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IOleObject_GetMoniker(IOleObject *iface, DWORD assign,
+ DWORD which_mon, IMoniker **mon)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IOleObject_GetUserClassID(IOleObject *iface, CLSID *clsid)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IOleObject_GetUserType(IOleObject *iface, DWORD form, LPOLESTR *utype)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IOleObject_InitFromData(IOleObject *iface,
+ IDataObject *dobj, BOOL creation, DWORD res)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IOleObject_IsUpToDate(IOleObject *iface)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IOleObject_SetClientSite(IOleObject *iface, IOleClientSite *csite)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IOleObject_SetColorScheme(IOleObject *iface, LOGPALETTE *logpal)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IOleObject_SetExtent(IOleObject *iface, DWORD draw_asp, SIZEL *size)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IOleObject_SetHostNames(IOleObject *iface,
+ LPCOLESTR cont_app, LPCOLESTR cont_obj)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IOleObject_SetMoniker(IOleObject *iface, DWORD which_mon, IMoniker *mon)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IOleObject_Unadvise(IOleObject *iface, DWORD conn)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IOleObject_Update(IOleObject *iface)
+{
+ HANDLE update_event;
+
+ update_event = CreateEventA(NULL, FALSE, FALSE, "IOleObject_Update call in local server");
+ SetEvent(update_event);
+ CloseHandle(update_event);
+ return S_OK;
+}
+
+static const IOleObjectVtbl TC_IOleObject_Vtbl = {
+ TC_IOleObject_QueryInterface,
+ TC_IOleObject_AddRef,
+ TC_IOleObject_Release,
+ TC_IOleObject_SetClientSite,
+ TC_IOleObject_GetClientSite,
+ TC_IOleObject_SetHostNames,
+ TC_IOleObject_Close,
+ TC_IOleObject_SetMoniker,
+ TC_IOleObject_GetMoniker,
+ TC_IOleObject_InitFromData,
+ TC_IOleObject_GetClipboardData,
+ TC_IOleObject_DoVerb,
+ TC_IOleObject_EnumVerbs,
+ TC_IOleObject_Update,
+ TC_IOleObject_IsUpToDate,
+ TC_IOleObject_GetUserClassID,
+ TC_IOleObject_GetUserType,
+ TC_IOleObject_SetExtent,
+ TC_IOleObject_GetExtent,
+ TC_IOleObject_Advise,
+ TC_IOleObject_Unadvise,
+ TC_IOleObject_EnumAdvise,
+ TC_IOleObject_GetMiscStatus,
+ TC_IOleObject_SetColorScheme,
+};
+
+static HRESULT WINAPI TC_IDataObject_QueryInterface(IDataObject *iface, REFIID riid, void **ppv)
+{
+ return IUnknown_QueryInterface(&test_class->IUnknown_iface, riid, ppv);
+}
+
+static ULONG WINAPI TC_IDataObject_AddRef(IDataObject *iface)
+{
+ return IUnknown_AddRef(&test_class->IUnknown_iface);
+}
+
+static ULONG WINAPI TC_IDataObject_Release(IDataObject *iface)
+{
+ return IUnknown_Release(&test_class->IUnknown_iface);
+}
+
+static HRESULT WINAPI TC_IDataObject_DAdvise(IDataObject *iface, FORMATETC *fmt,
+ DWORD adv, LPADVISESINK advs, DWORD *conn)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IDataObject_DUnadvise(IDataObject *iface, DWORD conn)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IDataObject_EnumDAdvise(IDataObject *iface, IEnumSTATDATA **stat)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IDataObject_EnumFormatEtc(IDataObject *iface, DWORD dir, IEnumFORMATETC **fmt)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IDataObject_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *in, FORMATETC *out)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IDataObject_GetData(IDataObject *iface, FORMATETC *fmt, STGMEDIUM *stg)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IDataObject_GetDataHere(IDataObject *iface, FORMATETC *fmt, STGMEDIUM *stg)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IDataObject_QueryGetData(IDataObject *iface, FORMATETC *fmt)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IDataObject_SetData(IDataObject *iface, FORMATETC *fmt, STGMEDIUM *med, BOOL rel)
+{
+ return E_NOTIMPL;
+}
+
+static const IDataObjectVtbl TC_IDataObject_Vtbl = {
+ TC_IDataObject_QueryInterface,
+ TC_IDataObject_AddRef,
+ TC_IDataObject_Release,
+ TC_IDataObject_GetData,
+ TC_IDataObject_GetDataHere,
+ TC_IDataObject_QueryGetData,
+ TC_IDataObject_GetCanonicalFormatEtc,
+ TC_IDataObject_SetData,
+ TC_IDataObject_EnumFormatEtc,
+ TC_IDataObject_DAdvise,
+ TC_IDataObject_DUnadvise,
+ TC_IDataObject_EnumDAdvise,
+};
+
+static HRESULT WINAPI TC_IPersistStorage_QueryInterface(IPersistStorage *iface, REFIID riid, void **ppv)
+{
+ return IUnknown_QueryInterface(&test_class->IUnknown_iface, riid, ppv);
+}
+
+static ULONG WINAPI TC_IPersistStorage_AddRef(IPersistStorage *iface)
+{
+ return IUnknown_AddRef(&test_class->IUnknown_iface);
+}
+
+static ULONG WINAPI TC_IPersistStorage_Release(IPersistStorage *iface)
+{
+ return IUnknown_Release(&test_class->IUnknown_iface);
+}
+
+static HRESULT WINAPI TC_IPersistStorage_GetClassID(IPersistStorage *iface, CLSID *clsid)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IPersistStorage_IsDirty(IPersistStorage *iface)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IPersistStorage_InitNew(IPersistStorage *iface, IStorage *stg)
+{
+ HANDLE update_event;
+
+ update_event = CreateEventA(NULL, FALSE, FALSE, "IPersistStorage_InitNew call in local server");
+ SetEvent(update_event);
+ CloseHandle(update_event);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI TC_IPersistStorage_Load(IPersistStorage *iface, IStorage *stg)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IPersistStorage_Save(IPersistStorage *iface, IStorage *stg, BOOL same_as_load)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IPersistStorage_SaveCompleted(IPersistStorage *iface, IStorage *stg)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI TC_IPersistStorage_HandsOffStorage(IPersistStorage *iface)
+{
+ return E_NOTIMPL;
+}
+
+static const IPersistStorageVtbl TC_IPersistStorage_Vtbl = {
+ TC_IPersistStorage_QueryInterface,
+ TC_IPersistStorage_AddRef,
+ TC_IPersistStorage_Release,
+ TC_IPersistStorage_GetClassID,
+ TC_IPersistStorage_IsDirty,
+ TC_IPersistStorage_InitNew,
+ TC_IPersistStorage_Load,
+ TC_IPersistStorage_Save,
+ TC_IPersistStorage_SaveCompleted,
+ TC_IPersistStorage_HandsOffStorage,
+};
+
+static HRESULT create_testclass(IUnknown *pUnkOuter, REFIID riid, void **ppv)
+{
+ HRESULT hres;
+
+ test_class = HeapAlloc(GetProcessHeap(), 0, sizeof(TestClass));
+
+ if (!test_class)
+ return E_OUTOFMEMORY;
+
+ test_class->IUnknown_iface.lpVtbl = &TC_IUnknown_Vtbl;
+ test_class->IOleObject_iface.lpVtbl = &TC_IOleObject_Vtbl;
+ test_class->IDataObject_iface.lpVtbl = &TC_IDataObject_Vtbl;
+ test_class->IPersistStorage_iface.lpVtbl = &TC_IPersistStorage_Vtbl;
+ test_class->ref = 1;
+ test_class->clsid = CLSID_Test_Server;
+
+ hres = IUnknown_QueryInterface(&test_class->IUnknown_iface, riid, ppv);
+ ok(hres == S_OK, "QuereyInterface failed with error %x\n", hres);
+
+ return hres;
+}
static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
{
@@ -173,11 +451,13 @@ static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID r
*ppv = iface;
return S_OK;
}else if(IsEqualGUID(riid, &IID_IMarshal)) {
- CHECK_EXPECT(CF_QueryInterface_IMarshal);
*ppv = NULL;
return E_NOINTERFACE;
}else if(IsEqualGUID(riid, &IID_IClassFactory)) {
- CHECK_EXPECT(CF_QueryInterface_ClassFactory);
+ HANDLE cf_event;
+ cf_event = CreateEventA(NULL, FALSE, FALSE, "Local server's CF");
+ SetEvent(cf_event);
+ CloseHandle(cf_event);
*ppv = iface;
return S_OK;
}
@@ -200,7 +480,7 @@ static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface,
IUnknown *pUnkOuter, REFIID riid, void **ppv)
{
- CHECK_EXPECT(CF_CreateInstance);
+ HRESULT hres;
ok(pUnkOuter == NULL, "pUnkOuter != NULL\n");
todo_wine ok(IsEqualGUID(riid, &IID_IUnknown), "riid = %s\n", wine_dbgstr_guid(riid));
@@ -209,8 +489,10 @@ static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface,
return E_NOINTERFACE;
}
- *ppv = &test_class;
- return S_OK;
+ hres = create_testclass(pUnkOuter, riid, ppv);
+ ok(hres == S_OK, "create_testclass failed with error %x\n", hres);
+
+ return hres;
}
static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL fLock)
@@ -229,91 +511,184 @@ static const IClassFactoryVtbl ClassFactoryVtbl = {
static IClassFactory ClassFactory = { &ClassFactoryVtbl };
-static void test_default_handler_run(void)
+static HRESULT create_storage(IStorage **stg)
{
- const CLSID test_server_clsid = {0x0f77e570,0x80c3,0x11e2,{0x9e,0x96,0x08,0x00,0x20,0x0c,0x9a,0x66}};
+ HRESULT hr;
+ ILockBytes *lock_bytes;
- IUnknown *unk;
+ hr = CreateILockBytesOnHGlobal(NULL, TRUE, &lock_bytes);
+ if(SUCCEEDED(hr))
+ {
+ hr = StgCreateDocfileOnILockBytes(lock_bytes,
+ STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, stg);
+ ILockBytes_Release(lock_bytes);
+ }
+ return hr;
+}
+
+static LONG register_server(void)
+{
+ LONG ret;
+ HKEY root;
+ char server_path[MAX_PATH];
+
+ lstrcpyA(server_path, wine_argv[0]);
+ lstrcatA(server_path, " defaulthandler");
+
+ StringFromGUID2(&CLSID_Test_Server, &clsid_key[6], CHARS_IN_GUID);
+
+ ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_key, 0, NULL, 0,
+ KEY_READ | KEY_WRITE | KEY_CREATE_SUB_KEY, NULL, &root, NULL);
+ if (ret == ERROR_SUCCESS)
+ {
+ ret = RegSetValueA(root, "LocalServer32", REG_SZ, server_path, strlen(server_path));
+ if (ret != ERROR_SUCCESS)
+ RegDeleteKeyA(root, "LocalServer32");
+ RegCloseKey(root);
+ }
+
+ return ret;
+}
+
+static void unregister_server(void)
+{
+ HKEY root;
+ LONG ret;
+
+ StringFromGUID2(&CLSID_Test_Server, &clsid_key[6], CHARS_IN_GUID);
+
+ if (RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_key, 0, NULL, 0,
+ DELETE, NULL, &root, NULL) == ERROR_SUCCESS)
+ {
+ ret = RegDeleteKeyA(root, "LocalServer32");
+ ok(ret == ERROR_SUCCESS, "RegDeleteKey error %u\n", ret);
+ ret = RegDeleteKeyA(root, "");
+ ok(ret == ERROR_SUCCESS, "RegDeleteKey error %u\n", ret);
+ RegCloseKey(root);
+ }
+}
+
+static void run_local_server(void)
+{
+ DWORD class_reg;
+ HRESULT hres;
+ HANDLE finish_event;
+
+ hres = CoRegisterClassObject(&CLSID_Test_Server, (IUnknown*)&ClassFactory,
+ CLSCTX_LOCAL_SERVER, 0, &class_reg);
+ ok(hres == S_OK, "CoRegisterClassObject failed: %x\n", hres);
+
+ finish_event = CreateEventA(NULL, FALSE, FALSE, "Shutdown local server");
+ WaitForSingleObject(finish_event, INFINITE);
+ CloseHandle(finish_event);
+ CoRevokeClassObject(class_reg);
+}
+
+static void test_running_object(void)
+{
IRunnableObject *ro;
IOleObject *oleobj;
- IPersistStorage *persist;
- DWORD class_reg;
+ IStorage *stg;
HRESULT hres;
+ HANDLE update_event, finish_event, cf_event;
+ IPersistStorage *persist;
- if(!GetProcAddress(GetModuleHandleA("ole32"), "CoRegisterSurrogateEx")) {
- win_skip("skipping OleCreateDefaultHandler tests\n");
- return;
- }
-
- hres = CoRegisterClassObject(&test_server_clsid, (IUnknown*)&ClassFactory,
- CLSCTX_INPROC_SERVER, 0, &class_reg);
- ok(hres == S_OK, "CoRegisterClassObject failed: %x\n", hres);
-
- hres = OleCreateDefaultHandler(&test_server_clsid, NULL, &IID_IUnknown, (void**)&unk);
- ok(hres == S_OK, "OleCreateDefaultHandler failed: %x\n", hres);
-
- hres = IUnknown_QueryInterface(unk, &IID_IRunnableObject, (void**)&ro);
+ hres = IUnknown_QueryInterface(dfhandler_unk, &IID_IRunnableObject, (void**)&ro);
ok(hres == S_OK, "QueryInterface(IRunnableObject) failed: %x\n", hres);
- IUnknown_Release(unk);
+ hres = IRunnableObject_IsRunning(ro);
+ ok(hres == FALSE, "Object shouldn't be running\n");
+
+ /* set object running and expect delegated calls */
+ hres = IUnknown_QueryInterface(dfhandler_unk, &IID_IOleObject, (void**)&oleobj);
+ ok(hres == S_OK, "QueryInterface(IOleObject) failed: %x\n", hres);
+ update_event = CreateEventA(NULL, FALSE, FALSE, "IOleObject_Update call in local server");
+ cf_event = CreateEventA(NULL, FALSE, FALSE, "Local server's CF");
hres = IRunnableObject_Run(ro, NULL);
- ok(hres == REGDB_E_CLASSNOTREG, "Run returned: %x, expected REGDB_E_CLASSNOTREG\n", hres);
- IRunnableObject_Release(ro);
+ todo_wine ok(hres == S_OK, "Failed to run object. Returned value was %x\n", hres);
+ hres = IRunnableObject_IsRunning(ro);
+ todo_wine ok(hres == TRUE, "Object should be running\n");
- SET_EXPECT(CF_QueryInterface_IMarshal);
- CoRevokeClassObject(class_reg);
- todo_wine CHECK_CALLED(CF_QueryInterface_IMarshal);
+ SET_EXPECT(OleObject_Update);
+ hres = IOleObject_Update(oleobj);
+ todo_wine ok(hres == S_OK, "IOleObject_Update failed: %x\n", hres);
+ if (WaitForSingleObject(update_event, 3000) == WAIT_OBJECT_0)
+ CHECK_EXPECT2(OleObject_Update);
+ todo_wine CHECK_CALLED(OleObject_Update);
+ CloseHandle(update_event);
- hres = CoRegisterClassObject(&test_server_clsid, (IUnknown*)&ClassFactory,
- CLSCTX_LOCAL_SERVER, 0, &class_reg);
- ok(hres == S_OK, "CoRegisterClassObject failed: %x\n", hres);
+ SET_EXPECT(CF_QueryInterface_ClassFactory);
+ if (WaitForSingleObject(cf_event, 3000) == WAIT_OBJECT_0)
+ CHECK_EXPECT2(CF_QueryInterface_ClassFactory);
+ CHECK_CALLED(CF_QueryInterface_ClassFactory);
+ CloseHandle(cf_event);
- hres = OleCreateDefaultHandler(&test_server_clsid, NULL, &IID_IUnknown, (void**)&unk);
- ok(hres == S_OK, "OleCreateDefaultHandler failed: %x\n", hres);
-
- hres = IUnknown_QueryInterface(unk, &IID_IOleObject, (void**)&oleobj);
- ok(hres == S_OK, "QueryInterface(IID_IOleObject) failed: %x\n", hres);
+ /* test delegation to object's IPersistStorage */
+ hres = create_storage(&stg);
+ ok(hres == S_OK, "got %08x\n", hres);
hres = IOleObject_QueryInterface(oleobj, &IID_IPersistStorage, (void**)&persist);
- ok(hres == S_OK, "QueryInterface(IID_IPersistStorage) failed: %x\n", hres);
+ ok(hres == S_OK, "got %08x\n", hres);
+
+ update_event = CreateEventA(NULL, FALSE, FALSE, "IPersistStorage_InitNew call in local server");
+ SET_EXPECT(PStorage_InitNew);
+ hres = IPersistStorage_InitNew(persist, stg);
+ ok(hres == S_OK, "got %08x\n", hres);
+ if (WaitForSingleObject(update_event, 3000) == WAIT_OBJECT_0)
+ CHECK_EXPECT2(PStorage_InitNew);
+ todo_wine CHECK_CALLED(PStorage_InitNew);
+ CloseHandle(update_event);
+
IPersistStorage_Release(persist);
IOleObject_Release(oleobj);
-
- hres = IUnknown_QueryInterface(unk, &IID_IRunnableObject, (void**)&ro);
- ok(hres == S_OK, "QueryInterface(IRunnableObject) failed: %x\n", hres);
- IUnknown_Release(unk);
-
- SET_EXPECT(CF_QueryInterface_ClassFactory);
- SET_EXPECT(CF_CreateInstance);
- hres = IRunnableObject_Run(ro, NULL);
-todo_wine
- ok(hres == S_OK, "Run failed: %x\n", hres);
- CHECK_CALLED(CF_QueryInterface_ClassFactory);
- CHECK_CALLED(CF_CreateInstance);
IRunnableObject_Release(ro);
+ IStorage_Release(stg);
- SET_EXPECT(CF_QueryInterface_ClassFactory);
- SET_EXPECT(CF_CreateInstance);
- hres = CoCreateInstance(&test_server_clsid, NULL, CLSCTX_LOCAL_SERVER,
- &IID_IOleObject, (void**)&oleobj);
-todo_wine
- ok(hres == REGDB_E_CLASSNOTREG, "expected REGDB_E_CLASSNOTREG, got %x\n", hres);
-todo_wine
- CHECK_NOT_CALLED(CF_QueryInterface_ClassFactory);
-todo_wine
- CHECK_NOT_CALLED(CF_CreateInstance);
-
- SET_EXPECT(CF_QueryInterface_IMarshal);
- CoRevokeClassObject(class_reg);
- todo_wine CHECK_CALLED(CF_QueryInterface_IMarshal);
+ finish_event = CreateEventA(NULL, FALSE, FALSE, "Shutdown local server");
+ SetEvent(finish_event);
+ CloseHandle(finish_event);
}
START_TEST(defaulthandler)
{
+ HRESULT hres;
+
+ wine_argc = winetest_get_mainargs( &wine_argv );
+ if (wine_argc > 2 && !strncmp(wine_argv[2], "-Embedding", strnlen(wine_argv[2], 10)))
+ {
+ CoInitializeEx(NULL, COINIT_MULTITHREADED);
+ run_local_server();
+ CoUninitialize();
+ return;
+ }
+
OleInitialize(NULL);
- test_olestream();
- test_default_handler_run();
+ if (register_server() != ERROR_SUCCESS)
+ {
+ win_skip("not enough permissions to create a server CLSID key\n");
+ OleUninitialize();
+ return;
+ }
+ hres = OleCreateDefaultHandler(&CLSID_Test_Server, NULL, &IID_IUnknown, (void**)&dfhandler_unk);
+ ok(hres == S_OK, "OleCreateDefaultHandler failed: %x\n", hres);
+
+ if (FAILED(hres)) goto fail;
+
+ test_running_object();
+ /*
+ * TODO:
+ * - Test aggregating default handler from a custom handler.
+ * - Test delegation to datacache.
+ * - Test handler for non-running object. Some functions must
+ * save information for later delegation to object.
+ */
+
+ hres = IUnknown_Release(dfhandler_unk);
+ ok(hres == S_OK, "Failed to release default handler's IUnknown: %x\n", hres);
+
+fail:
+ unregister_server();
OleUninitialize();
}
--
2.14.1