/* * Default Handler Tests * * Copyright 2008 Huw Davies * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #define COBJMACROS #define CONST_VTABLE #include #include #include "windef.h" #include "winbase.h" #include "objbase.h" #include "wine/test.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 CHECK_NOT_CALLED(func) \ do { \ ok(!called_ ## func, "unexpected " #func "\n"); \ expect_ ## func = called_ ## func = FALSE; \ }while(0) DEFINE_EXPECT(CF_QueryInterface_ClassFactory); DEFINE_EXPECT(CF_CreateInstance); DEFINE_EXPECT(CF_QueryInterface_IMarshal); static HRESULT create_storage(IStorage **stg) { 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) { if(IsEqualGUID(riid, &IID_IUnknown)) { *ppv = iface; return S_OK; }else if(IsEqualGUID(riid, &IID_IOleObject)) { ok(0, "unexpected query for IOleObject interface\n"); *ppv = NULL; return E_NOINTERFACE; } *ppv = NULL; return E_NOINTERFACE; } static ULONG WINAPI test_class_AddRef(IUnknown *iface) { return 2; } static ULONG WINAPI test_class_Release(IUnknown *iface) { return 1; } static const IUnknownVtbl test_class_vtbl = { test_class_QueryInterface, test_class_AddRef, test_class_Release, }; static IUnknown test_class = { &test_class_vtbl }; static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) { if(IsEqualGUID(riid, &IID_IUnknown)) { *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); *ppv = iface; return S_OK; } ok(0, "unexpected interface: %s\n", wine_dbgstr_guid(riid)); *ppv = NULL; return E_NOINTERFACE; } static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) { return 2; } static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) { return 1; } static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppv) { CHECK_EXPECT(CF_CreateInstance); ok(pUnkOuter == NULL, "pUnkOuter != NULL\n"); todo_wine ok(IsEqualGUID(riid, &IID_IUnknown), "riid = %s\n", wine_dbgstr_guid(riid)); if(IsEqualGUID(riid, &IID_IOleObject)) { *ppv = NULL; return E_NOINTERFACE; } *ppv = &test_class; return S_OK; } static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL fLock) { ok(0, "unexpected call\n"); return E_NOTIMPL; } static const IClassFactoryVtbl ClassFactoryVtbl = { ClassFactory_QueryInterface, ClassFactory_AddRef, ClassFactory_Release, ClassFactory_CreateInstance, ClassFactory_LockServer }; static IClassFactory ClassFactory = { &ClassFactoryVtbl }; static void test_default_handler_run(void) { const CLSID test_server_clsid = {0x0f77e570,0x80c3,0x11e2,{0x9e,0x96,0x08,0x00,0x20,0x0c,0x9a,0x66}}; IUnknown *unk; IRunnableObject *ro; IOleObject *oleobj; IPersistStorage *persist; DWORD class_reg; HRESULT hres; 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); ok(hres == S_OK, "QueryInterface(IRunnableObject) failed: %x\n", hres); IUnknown_Release(unk); hres = IRunnableObject_Run(ro, NULL); ok(hres == REGDB_E_CLASSNOTREG, "Run returned: %x, expected REGDB_E_CLASSNOTREG\n", hres); IRunnableObject_Release(ro); SET_EXPECT(CF_QueryInterface_IMarshal); CoRevokeClassObject(class_reg); todo_wine CHECK_CALLED(CF_QueryInterface_IMarshal); hres = CoRegisterClassObject(&test_server_clsid, (IUnknown*)&ClassFactory, CLSCTX_LOCAL_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_IOleObject, (void**)&oleobj); ok(hres == S_OK, "QueryInterface(IID_IOleObject) failed: %x\n", hres); hres = IOleObject_QueryInterface(oleobj, &IID_IPersistStorage, (void**)&persist); ok(hres == S_OK, "QueryInterface(IID_IPersistStorage) failed: %x\n", hres); 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); 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); } START_TEST(defaulthandler) { OleInitialize(NULL); test_olestream(); test_default_handler_run(); OleUninitialize(); }