diff --git a/dlls/oledb32/tests/Makefile.in b/dlls/oledb32/tests/Makefile.in index 85a0ef34f05..fada4290dd6 100644 --- a/dlls/oledb32/tests/Makefile.in +++ b/dlls/oledb32/tests/Makefile.in @@ -3,10 +3,11 @@ TOPOBJDIR = ../../.. SRCDIR = @srcdir@ VPATH = @srcdir@ TESTDLL = oledb32.dll -IMPORTS = oleaut32 ole32 gdi32 advapi32 kernel32 +IMPORTS = oleaut32 ole32 user32 gdi32 advapi32 kernel32 CTESTS = \ - convert.c + convert.c \ + marshal.c IDL_I_SRCS = convert.idl diff --git a/dlls/oledb32/tests/marshal.c b/dlls/oledb32/tests/marshal.c new file mode 100644 index 00000000000..45fc3bc32c2 --- /dev/null +++ b/dlls/oledb32/tests/marshal.c @@ -0,0 +1,271 @@ +/* + * OLE DB Marshaling Tests + * + * Copyright 2009 Robert Shearman + * + * 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 _WIN32_DCOM +#define COBJMACROS +#define CONST_VTABLE + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "initguid.h" +#include "objbase.h" +#include "oledb.h" + +#include "wine/test.h" + +#define RELEASEMARSHALDATA WM_USER + +#define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08x\n", hr) + +struct host_object_data +{ + IStream *stream; + IID iid; + IUnknown *object; + MSHLFLAGS marshal_flags; + HANDLE marshal_event; + IMessageFilter *filter; +}; + +static DWORD CALLBACK host_object_proc(LPVOID p) +{ + struct host_object_data *data = p; + HRESULT hr; + MSG msg; + + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + if (data->filter) + { + IMessageFilter * prev_filter = NULL; + hr = CoRegisterMessageFilter(data->filter, &prev_filter); + if (prev_filter) IMessageFilter_Release(prev_filter); + ok_ole_success(hr, CoRegisterMessageFilter); + } + + hr = CoMarshalInterface(data->stream, &data->iid, data->object, MSHCTX_INPROC, NULL, data->marshal_flags); + ok_ole_success(hr, CoMarshalInterface); + + /* force the message queue to be created before signaling parent thread */ + PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); + + SetEvent(data->marshal_event); + + while (GetMessage(&msg, NULL, 0, 0)) + { + if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA) + { + CoReleaseMarshalData(data->stream); + SetEvent((HANDLE)msg.lParam); + } + else + DispatchMessage(&msg); + } + + HeapFree(GetProcessHeap(), 0, data); + + CoUninitialize(); + + return hr; +} + +static DWORD start_host_object2(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, IMessageFilter *filter, HANDLE *thread) +{ + DWORD tid = 0; + HANDLE marshal_event = CreateEvent(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; + + *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); + + 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); +} + +static void end_host_object(DWORD tid, HANDLE thread) +{ + BOOL ret = PostThreadMessage(tid, WM_QUIT, 0, 0); + ok(ret, "PostThreadMessage failed with error %d\n", GetLastError()); + /* be careful of races - don't return until hosting thread has terminated */ + ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" ); + CloseHandle(thread); +} + +#define TEST_PROPID 0xdead +static const WCHAR wszDBPropertyTestString[] = {'D','B','P','r','o','p','e','r','t','y','T','e','s','t','S','t','r','i','n','g',0}; +static const WCHAR wszDBPropertyColumnName[] = {'C','o','l','u','m','n',0}; + +static HRESULT WINAPI Test_DBProperties_QueryInterface( + IDBProperties* iface, + REFIID riid, + void **ppvObject) +{ + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IDBProperties)) + { + *ppvObject = iface; + return S_OK; + } + *ppvObject = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI Test_DBProperties_AddRef( + IDBProperties* iface) +{ + return 2; +} + +static ULONG WINAPI Test_DBProperties_Release( + IDBProperties* iface) +{ + return 1; +} + + /*** IDBProperties methods ***/ +static HRESULT WINAPI Test_DBProperties_GetProperties( + IDBProperties* iface, + ULONG cPropertyIDSets, + const DBPROPIDSET rgPropertyIDSets[], + ULONG *pcPropertySets, + DBPROPSET **prgPropertySets) +{ + ok(cPropertyIDSets == 0, "Expected cPropertyIDSets to be 0 instead of %d\n", cPropertyIDSets); + ok(*pcPropertySets == 1, "Expected *pcPropertySets to be 1 instead of %d\n", *pcPropertySets); + prgPropertySets[0] = CoTaskMemAlloc(sizeof(DBPROPSET)); + prgPropertySets[0]->rgProperties = CoTaskMemAlloc(sizeof(DBPROP)); + prgPropertySets[0]->rgProperties[0].dwPropertyID = TEST_PROPID; + prgPropertySets[0]->rgProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED; + prgPropertySets[0]->rgProperties[0].dwStatus = S_OK; + prgPropertySets[0]->rgProperties[0].colid.eKind = DBKIND_GUID_NAME; + /* colid contents */ + prgPropertySets[0]->rgProperties[0].colid.uGuid.guid = IID_IDBProperties; + prgPropertySets[0]->rgProperties[0].colid.uName.pwszName = CoTaskMemAlloc(sizeof(wszDBPropertyColumnName)); + memcpy(prgPropertySets[0]->rgProperties[0].colid.uName.pwszName, wszDBPropertyColumnName, sizeof(wszDBPropertyColumnName)); + /* vValue contents */ + V_VT(&prgPropertySets[0]->rgProperties[0].vValue) = VT_BSTR; + V_BSTR(&prgPropertySets[0]->rgProperties[0].vValue) = SysAllocString(wszDBPropertyTestString); + prgPropertySets[0]->cProperties = 1; + prgPropertySets[0]->guidPropertySet = IID_IDBProperties; + + return S_OK; +} + +static HRESULT WINAPI Test_DBProperties_GetPropertyInfo( + IDBProperties* iface, + ULONG cPropertyIDSets, + const DBPROPIDSET rgPropertyIDSets[], + ULONG *pcPropertyInfoSets, + DBPROPINFOSET **prgPropertyInfoSets, + OLECHAR **ppDescBuffer) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI Test_DBProperties_SetProperties( + IDBProperties* iface, + ULONG cPropertySets, + DBPROPSET rgPropertySets[]) +{ + return E_NOTIMPL; +} + +static const IDBPropertiesVtbl Test_DBProperties_Vtbl = +{ + Test_DBProperties_QueryInterface, + Test_DBProperties_AddRef, + Test_DBProperties_Release, + Test_DBProperties_GetProperties, + Test_DBProperties_GetPropertyInfo, + Test_DBProperties_SetProperties, +}; + +static IDBProperties Test_DBProperties = +{ + &Test_DBProperties_Vtbl +}; + +static void test_IDBProperties(void) +{ + HRESULT hr; + IStream *pStream = NULL; + IDBProperties *pProxy = NULL; + DWORD tid; + HANDLE thread; + static const LARGE_INTEGER ullZero; + ULONG propset_count; + DBPROPSET *propsets = NULL; + + hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream); + ok_ole_success(hr, "CreateStreamOnHGlobal"); + tid = start_host_object(pStream, &IID_IDBProperties, (IUnknown*)&Test_DBProperties, MSHLFLAGS_NORMAL, &thread); + + IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL); + hr = CoUnmarshalInterface(pStream, &IID_IDBProperties, (void **)&pProxy); + ok_ole_success(hr, "CoUnmarshalInterface"); + IStream_Release(pStream); + + propset_count = 1; + hr = IDBProperties_GetProperties(pProxy, 0, NULL, &propset_count, &propsets); + ok_ole_success(hr, "IDBProperties_GetProperties"); + + ok(propset_count == 1, "Expected propset_count of 1 but got %d\n", propset_count); + ok(propsets->rgProperties[0].dwPropertyID == TEST_PROPID, "Expected property ID of 0x%x, but got 0x%x\n", TEST_PROPID, propsets->rgProperties[0].dwPropertyID); + ok(propsets->rgProperties[0].dwOptions == DBPROPOPTIONS_REQUIRED, "Expected property options of 0x%x, but got 0x%x\n", DBPROPOPTIONS_REQUIRED, propsets->rgProperties[0].dwOptions); + ok(propsets->rgProperties[0].dwStatus == S_OK, "Expected property options of 0x%x, but got 0x%x\n", S_OK, propsets->rgProperties[0].dwStatus); + ok(propsets->rgProperties[0].colid.eKind == DBKIND_GUID_NAME, "Expected property colid kind of DBKIND_GUID_NAME, but got %d\n", propsets->rgProperties[0].colid.eKind); + /* colid contents */ + ok(IsEqualGUID(&propsets->rgProperties[0].colid.uGuid.guid, &IID_IDBProperties), "Unexpected property colid guid\n"); + ok(!lstrcmpW(propsets->rgProperties[0].colid.uName.pwszName, wszDBPropertyColumnName), "Unexpected property colid name\n"); + /* vValue contents */ + ok(V_VT(&propsets->rgProperties[0].vValue) == VT_BSTR, "Expected property value vt of VT_BSTR, but got %d\n", V_VT(&propsets->rgProperties[0].vValue)); + ok(!lstrcmpW(V_BSTR(&propsets->rgProperties[0].vValue), wszDBPropertyTestString), "Unexpected property value string\n"); + ok(propsets->cProperties == 1, "Expected property count of 1 but got %d\n", propsets->cProperties); + ok(IsEqualGUID(&propsets->guidPropertySet, &IID_IDBProperties), "Unexpected guid for property set\n"); + + IDBProperties_Release(pProxy); + + end_host_object(tid, thread); +} + +START_TEST(marshal) +{ + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + test_IDBProperties(); + CoUninitialize(); +}