oledb32: Fix IDBProperties::GetProperties test on Windows.
[wine] / dlls / oledb32 / tests / marshal.c
1 /*
2  * OLE DB Marshaling Tests
3  *
4  * Copyright 2009 Robert Shearman
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define _WIN32_DCOM
22 #define COBJMACROS
23 #define CONST_VTABLE
24
25 #include <stdarg.h>
26 #include <stdio.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "initguid.h"
31 #include "objbase.h"
32 #include "oledb.h"
33
34 #include "wine/test.h"
35
36 #define RELEASEMARSHALDATA WM_USER
37
38 #define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08x\n", hr)
39
40 struct host_object_data
41 {
42     IStream *stream;
43     IID iid;
44     IUnknown *object;
45     MSHLFLAGS marshal_flags;
46     HANDLE marshal_event;
47     IMessageFilter *filter;
48 };
49
50 static DWORD CALLBACK host_object_proc(LPVOID p)
51 {
52     struct host_object_data *data = p;
53     HRESULT hr;
54     MSG msg;
55
56     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
57
58     if (data->filter)
59     {
60         IMessageFilter * prev_filter = NULL;
61         hr = CoRegisterMessageFilter(data->filter, &prev_filter);
62         if (prev_filter) IMessageFilter_Release(prev_filter);
63         ok_ole_success(hr, CoRegisterMessageFilter);
64     }
65
66     hr = CoMarshalInterface(data->stream, &data->iid, data->object, MSHCTX_INPROC, NULL, data->marshal_flags);
67     ok_ole_success(hr, CoMarshalInterface);
68
69     /* force the message queue to be created before signaling parent thread */
70     PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
71
72     SetEvent(data->marshal_event);
73
74     while (GetMessage(&msg, NULL, 0, 0))
75     {
76         if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA)
77         {
78             CoReleaseMarshalData(data->stream);
79             SetEvent((HANDLE)msg.lParam);
80         }
81         else
82             DispatchMessage(&msg);
83     }
84
85     HeapFree(GetProcessHeap(), 0, data);
86
87     CoUninitialize();
88
89     return hr;
90 }
91
92 static DWORD start_host_object2(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, IMessageFilter *filter, HANDLE *thread)
93 {
94     DWORD tid = 0;
95     HANDLE marshal_event = CreateEvent(NULL, FALSE, FALSE, NULL);
96     struct host_object_data *data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
97
98     data->stream = stream;
99     data->iid = *riid;
100     data->object = object;
101     data->marshal_flags = marshal_flags;
102     data->marshal_event = marshal_event;
103     data->filter = filter;
104
105     *thread = CreateThread(NULL, 0, host_object_proc, data, 0, &tid);
106
107     /* wait for marshaling to complete before returning */
108     ok( !WaitForSingleObject(marshal_event, 10000), "wait timed out\n" );
109     CloseHandle(marshal_event);
110
111     return tid;
112 }
113
114 static DWORD start_host_object(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, HANDLE *thread)
115 {
116     return start_host_object2(stream, riid, object, marshal_flags, NULL, thread);
117 }
118
119 static void end_host_object(DWORD tid, HANDLE thread)
120 {
121     BOOL ret = PostThreadMessage(tid, WM_QUIT, 0, 0);
122     ok(ret, "PostThreadMessage failed with error %d\n", GetLastError());
123     /* be careful of races - don't return until hosting thread has terminated */
124     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
125     CloseHandle(thread);
126 }
127
128 #define TEST_PROPID 0xdead
129 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};
130 static const WCHAR wszDBPropertyColumnName[] = {'C','o','l','u','m','n',0};
131
132 static HRESULT WINAPI Test_DBProperties_QueryInterface(
133     IDBProperties* iface,
134     REFIID riid,
135     void **ppvObject)
136 {
137     if (IsEqualIID(riid, &IID_IUnknown) ||
138         IsEqualIID(riid, &IID_IDBProperties))
139     {
140         *ppvObject = iface;
141         return S_OK;
142     }
143     *ppvObject = NULL;
144     return E_NOINTERFACE;
145 }
146
147 static ULONG WINAPI Test_DBProperties_AddRef(
148         IDBProperties* iface)
149 {
150     return 2;
151 }
152
153 static ULONG WINAPI Test_DBProperties_Release(
154         IDBProperties* iface)
155 {
156     return 1;
157 }
158
159     /*** IDBProperties methods ***/
160 static HRESULT WINAPI Test_DBProperties_GetProperties(
161         IDBProperties* iface,
162         ULONG cPropertyIDSets,
163         const DBPROPIDSET rgPropertyIDSets[],
164         ULONG *pcPropertySets,
165         DBPROPSET **prgPropertySets)
166 {
167     ok(cPropertyIDSets == 0, "Expected cPropertyIDSets to be 0 instead of %d\n", cPropertyIDSets);
168     todo_wine
169     ok(*pcPropertySets == 0, "Expected *pcPropertySets to be 0 instead of %d\n", *pcPropertySets);
170     *pcPropertySets = 1;
171     prgPropertySets[0] = CoTaskMemAlloc(sizeof(DBPROPSET));
172     prgPropertySets[0]->rgProperties = CoTaskMemAlloc(sizeof(DBPROP));
173     prgPropertySets[0]->rgProperties[0].dwPropertyID = TEST_PROPID;
174     prgPropertySets[0]->rgProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;
175     prgPropertySets[0]->rgProperties[0].dwStatus = S_OK;
176     prgPropertySets[0]->rgProperties[0].colid.eKind = DBKIND_GUID_NAME;
177     /* colid contents */
178     prgPropertySets[0]->rgProperties[0].colid.uGuid.guid = IID_IDBProperties;
179     prgPropertySets[0]->rgProperties[0].colid.uName.pwszName = CoTaskMemAlloc(sizeof(wszDBPropertyColumnName));
180     memcpy(prgPropertySets[0]->rgProperties[0].colid.uName.pwszName, wszDBPropertyColumnName, sizeof(wszDBPropertyColumnName));
181     /* vValue contents */
182     V_VT(&prgPropertySets[0]->rgProperties[0].vValue) = VT_BSTR;
183     V_BSTR(&prgPropertySets[0]->rgProperties[0].vValue) = SysAllocString(wszDBPropertyTestString);
184     prgPropertySets[0]->cProperties = 1;
185     prgPropertySets[0]->guidPropertySet = IID_IDBProperties;
186
187     return S_OK;
188 }
189
190 static HRESULT WINAPI Test_DBProperties_GetPropertyInfo(
191         IDBProperties* iface,
192         ULONG cPropertyIDSets,
193         const DBPROPIDSET rgPropertyIDSets[],
194         ULONG *pcPropertyInfoSets,
195         DBPROPINFOSET **prgPropertyInfoSets,
196         OLECHAR **ppDescBuffer)
197 {
198     return E_NOTIMPL;
199 }
200
201 static HRESULT WINAPI Test_DBProperties_SetProperties(
202         IDBProperties* iface,
203         ULONG cPropertySets,
204         DBPROPSET rgPropertySets[])
205 {
206     return E_NOTIMPL;
207 }
208
209 static const IDBPropertiesVtbl Test_DBProperties_Vtbl =
210 {
211     Test_DBProperties_QueryInterface,
212     Test_DBProperties_AddRef,
213     Test_DBProperties_Release,
214     Test_DBProperties_GetProperties,
215     Test_DBProperties_GetPropertyInfo,
216     Test_DBProperties_SetProperties,
217 };
218
219 static IDBProperties Test_DBProperties =
220 {
221     &Test_DBProperties_Vtbl
222 };
223
224 static void test_IDBProperties(void)
225 {
226     HRESULT hr;
227     IStream *pStream = NULL;
228     IDBProperties *pProxy = NULL;
229     DWORD tid;
230     HANDLE thread;
231     static const LARGE_INTEGER ullZero;
232     ULONG propset_count;
233     DBPROPSET *propsets = NULL;
234
235     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
236     ok_ole_success(hr, "CreateStreamOnHGlobal");
237     tid = start_host_object(pStream, &IID_IDBProperties, (IUnknown*)&Test_DBProperties, MSHLFLAGS_NORMAL, &thread);
238
239     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
240     hr = CoUnmarshalInterface(pStream, &IID_IDBProperties, (void **)&pProxy);
241     ok_ole_success(hr, "CoUnmarshalInterface");
242     IStream_Release(pStream);
243
244     propset_count = 1;
245     hr = IDBProperties_GetProperties(pProxy, 0, NULL, &propset_count, &propsets);
246     ok(hr == S_OK, "IDBProperties_GetProperties failed with error 0x%08x", hr);
247
248     ok(propset_count == 1, "Expected propset_count of 1 but got %d\n", propset_count);
249     ok(propsets->rgProperties[0].dwPropertyID == TEST_PROPID, "Expected property ID of 0x%x, but got 0x%x\n", TEST_PROPID, propsets->rgProperties[0].dwPropertyID);
250     ok(propsets->rgProperties[0].dwOptions == DBPROPOPTIONS_REQUIRED, "Expected property options of 0x%x, but got 0x%x\n", DBPROPOPTIONS_REQUIRED, propsets->rgProperties[0].dwOptions);
251     ok(propsets->rgProperties[0].dwStatus == S_OK, "Expected property options of 0x%x, but got 0x%x\n", S_OK, propsets->rgProperties[0].dwStatus);
252     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);
253     /* colid contents */
254     ok(IsEqualGUID(&propsets->rgProperties[0].colid.uGuid.guid, &IID_IDBProperties), "Unexpected property colid guid\n");
255     ok(!lstrcmpW(propsets->rgProperties[0].colid.uName.pwszName, wszDBPropertyColumnName), "Unexpected property colid name\n");
256     /* vValue contents */
257     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));
258     ok(!lstrcmpW(V_BSTR(&propsets->rgProperties[0].vValue), wszDBPropertyTestString), "Unexpected property value string\n");
259     ok(propsets->cProperties == 1, "Expected property count of 1 but got %d\n", propsets->cProperties);
260     ok(IsEqualGUID(&propsets->guidPropertySet, &IID_IDBProperties), "Unexpected guid for property set\n");
261
262     IDBProperties_Release(pProxy);
263
264     end_host_object(tid, thread);
265 }
266
267 START_TEST(marshal)
268 {
269     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
270
271     test_IDBProperties();
272     CoUninitialize();
273 }