Module: wine Branch: refs/heads/master Commit: fac6bedda9e78f8cd4e015f8afcf551b52adb411 URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=fac6bedda9e78f8cd4e015f8... Author: Robert Shearman <rob(a)codeweavers.com> Date: Fri Jul 14 17:13:58 2006 +0100 ole32: Improve CoRegisterMessageFilter and add tests for it. --- dlls/ole32/compobj.c | 44 +++++++++++++++- dlls/ole32/tests/compobj.c | 119 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+), 3 deletions(-) diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index db0fcbe..c89d8ce 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -2410,15 +2410,53 @@ DWORD WINAPI CoGetCurrentProcess(void) * RETURNS * Success: S_OK. * Failure: HRESULT code. + * + * NOTES + * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL + * lpMessageFilter removes the message filter. + * + * If lplpMessageFilter is not NULL the previous message filter will be + * returned in the memory pointer to this parameter and the caller is + * responsible for releasing the object. + * + * The current thread be in an apartment otherwise the function will crash. */ HRESULT WINAPI CoRegisterMessageFilter( LPMESSAGEFILTER lpMessageFilter, LPMESSAGEFILTER *lplpMessageFilter) { - FIXME("stub\n"); - if (lplpMessageFilter) { - *lplpMessageFilter = NULL; + struct apartment *apt; + IMessageFilter *lpOldMessageFilter; + + TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter); + + apt = COM_CurrentApt(); + + /* can't set a message filter in a multi-threaded apartment */ + if (apt->multi_threaded) + { + ERR("can't set message filter in MTA\n"); + return CO_E_NOT_SUPPORTED; } + + if (lpMessageFilter) + IMessageFilter_AddRef(lpMessageFilter); + + EnterCriticalSection(&apt->cs); + + lpOldMessageFilter = apt->filter; + apt->filter = lpMessageFilter; + + LeaveCriticalSection(&apt->cs); + + if (lplpMessageFilter) + *lplpMessageFilter = lpOldMessageFilter; + else if (lpOldMessageFilter) + IMessageFilter_Release(lpOldMessageFilter); + + if (lpMessageFilter) + FIXME("message filter has been registered, but will not be used\n"); + return S_OK; } diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c index 9164be8..19a6faa 100644 --- a/dlls/ole32/tests/compobj.c +++ b/dlls/ole32/tests/compobj.c @@ -29,6 +29,9 @@ #include "shlguid.h" #include "wine/test.h" +/* functions that are not present on all versions of Windows */ +HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit); + #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08lx\n", hr) static const CLSID CLSID_non_existent = { 0x12345678, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } }; @@ -142,12 +145,128 @@ static void test_ole_menu(void) DestroyWindow(hwndFrame); } + +static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj) +{ + if (ppvObj == NULL) return E_POINTER; + + if (IsEqualGUID(riid, &IID_IUnknown) || + IsEqualGUID(riid, &IID_IClassFactory)) + { + *ppvObj = (LPVOID)iface; + IMessageFilter_AddRef(iface); + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface) +{ + return 2; /* non-heap object */ +} + +static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface) +{ + return 1; /* non-heap object */ +} + +static DWORD WINAPI MessageFilter_HandleInComingCall( + IMessageFilter *iface, + DWORD dwCallType, + HTASK threadIDCaller, + DWORD dwTickCount, + LPINTERFACEINFO lpInterfaceInfo) +{ + trace("HandleInComingCall\n"); + return SERVERCALL_ISHANDLED; +} + +static DWORD WINAPI MessageFilter_RetryRejectedCall( + IMessageFilter *iface, + HTASK threadIDCallee, + DWORD dwTickCount, + DWORD dwRejectType) +{ + trace("RetryRejectedCall\n"); + return 0; +} + +static DWORD WINAPI MessageFilter_MessagePending( + IMessageFilter *iface, + HTASK threadIDCallee, + DWORD dwTickCount, + DWORD dwPendingType) +{ + trace("MessagePending\n"); + return PENDINGMSG_WAITNOPROCESS; +} + +static const IMessageFilterVtbl MessageFilter_Vtbl = +{ + MessageFilter_QueryInterface, + MessageFilter_AddRef, + MessageFilter_Release, + MessageFilter_HandleInComingCall, + MessageFilter_RetryRejectedCall, + MessageFilter_MessagePending +}; + +static IMessageFilter MessageFilter = { &MessageFilter_Vtbl }; + +static void test_CoRegisterMessageFilter(void) +{ + HRESULT hr; + IMessageFilter *prev_filter; + +#if 0 /* crashes without an apartment! */ + hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter); +#endif + + pCoInitializeEx(NULL, COINIT_MULTITHREADED); + prev_filter = (IMessageFilter *)0xdeadbeef; + hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter); + ok(hr == CO_E_NOT_SUPPORTED, + "CoRegisterMessageFilter should have failed with CO_E_NOT_SUPPORTED instead of 0x%08lx\n", + hr); + ok(prev_filter == (IMessageFilter *)0xdeadbeef, + "prev_filter should have been set to %p\n", prev_filter); + CoUninitialize(); + + pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + hr = CoRegisterMessageFilter(NULL, NULL); + ok_ole_success(hr, "CoRegisterMessageFilter"); + + prev_filter = (IMessageFilter *)0xdeadbeef; + hr = CoRegisterMessageFilter(NULL, &prev_filter); + ok_ole_success(hr, "CoRegisterMessageFilter"); + ok(prev_filter == NULL, "prev_filter should have been set to NULL instead of %p\n", prev_filter); + + hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter); + ok_ole_success(hr, "CoRegisterMessageFilter"); + ok(prev_filter == NULL, "prev_filter should have been set to NULL instead of %p\n", prev_filter); + + hr = CoRegisterMessageFilter(NULL, NULL); + ok_ole_success(hr, "CoRegisterMessageFilter"); + + CoUninitialize(); +} + START_TEST(compobj) { + HMODULE hOle32 = GetModuleHandle("ole32"); + if (!(pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx"))) + { + trace("You need DCOM95 installed to run this test\n"); + return; + } + test_ProgIDFromCLSID(); test_CLSIDFromProgID(); test_CLSIDFromString(); test_CoCreateInstance(); test_ole_menu(); test_CoGetClassObject(); + test_CoRegisterMessageFilter(); }