[PATCH] ole32/tests: Improve tests for OLE's default object handler.

Sergio Gómez Del Real sdelreal at codeweavers.com
Mon Apr 30 13:45:00 CDT 2018


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 at 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




More information about the wine-devel mailing list