dsound: Add dumb heuristic to find buggy applications, try 3
[wine/multimedia.git] / dlls / dispex / tests / marshal.c
blob7fa91214dd6fe99a4136ae083f1b317d2ffec680
1 /*
2 * Tests for marshaling IDispatchEx
4 * Copyright 2005-2006 Robert Shearman
5 * Copyright 2010 Huw Davies
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define COBJMACROS
24 #define CONST_VTABLE
26 #include <stdarg.h>
28 #include "initguid.h"
29 #include "objidl.h"
30 #include "dispex.h"
32 #include "wine/test.h"
34 #define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08lx\n", (unsigned long int)hr)
36 #define RELEASEMARSHALDATA WM_USER
38 struct host_object_data
40 IStream *stream;
41 IID iid;
42 IUnknown *object;
43 MSHLFLAGS marshal_flags;
44 HANDLE marshal_event;
45 HANDLE error_event;
46 IMessageFilter *filter;
49 static DWORD CALLBACK host_object_proc(LPVOID p)
51 struct host_object_data *data = p;
52 HRESULT hr;
53 MSG msg;
55 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
57 if (data->filter)
59 IMessageFilter * prev_filter = NULL;
60 hr = CoRegisterMessageFilter(data->filter, &prev_filter);
61 if (prev_filter) IMessageFilter_Release(prev_filter);
62 ok_ole_success(hr, CoRegisterMessageFilter);
65 hr = CoMarshalInterface(data->stream, &data->iid, data->object, MSHCTX_INPROC, NULL, data->marshal_flags);
67 /* force the message queue to be created before signaling parent thread */
68 PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
70 if(hr == S_OK)
71 SetEvent(data->marshal_event);
72 else
74 win_skip("IDispatchEx marshaller not available.\n");
75 SetEvent(data->error_event);
76 return hr;
79 while (GetMessage(&msg, NULL, 0, 0))
81 if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA)
83 trace("releasing marshal data\n");
84 CoReleaseMarshalData(data->stream);
85 SetEvent((HANDLE)msg.lParam);
87 else
88 DispatchMessage(&msg);
91 HeapFree(GetProcessHeap(), 0, data);
93 CoUninitialize();
95 return hr;
98 static DWORD start_host_object2(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, IMessageFilter *filter, HANDLE *thread)
100 DWORD tid = 0, ret;
101 HANDLE events[2];
102 struct host_object_data *data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
104 data->stream = stream;
105 data->iid = *riid;
106 data->object = object;
107 data->marshal_flags = marshal_flags;
108 data->marshal_event = events[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
109 data->error_event = events[1] = CreateEvent(NULL, FALSE, FALSE, NULL);
110 data->filter = filter;
112 *thread = CreateThread(NULL, 0, host_object_proc, data, 0, &tid);
114 /* wait for marshaling to complete before returning */
115 ret = WaitForMultipleObjects(2, events, FALSE, INFINITE);
116 CloseHandle(events[0]);
117 CloseHandle(events[1]);
119 if(ret == WAIT_OBJECT_0) return tid;
121 WaitForSingleObject(*thread, INFINITE);
122 CloseHandle(*thread);
123 *thread = INVALID_HANDLE_VALUE;
124 return 0;
127 static DWORD start_host_object(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, HANDLE *thread)
129 return start_host_object2(stream, riid, object, marshal_flags, NULL, thread);
132 static void end_host_object(DWORD tid, HANDLE thread)
134 BOOL ret = PostThreadMessage(tid, WM_QUIT, 0, 0);
135 ok(ret, "PostThreadMessage failed with error %d\n", GetLastError());
136 /* be careful of races - don't return until hosting thread has terminated */
137 WaitForSingleObject(thread, INFINITE);
138 CloseHandle(thread);
141 typedef struct
143 IDispatchEx IDispatchEx_iface;
144 LONG refs;
145 } dispex;
147 static inline dispex *impl_from_IDispatchEx(IDispatchEx *iface)
149 return CONTAINING_RECORD(iface, dispex, IDispatchEx_iface);
152 static HRESULT WINAPI dispex_QueryInterface(IDispatchEx* iface,
153 REFIID iid, void **obj)
155 trace("QI {%08x-...}\n", iid->Data1);
156 if(IsEqualIID(iid, &IID_IUnknown) ||
157 IsEqualIID(iid, &IID_IDispatchEx))
159 IDispatchEx_AddRef(iface);
160 *obj = iface;
161 return S_OK;
163 else
165 *obj = NULL;
166 return E_NOINTERFACE;
170 static ULONG WINAPI dispex_AddRef(IDispatchEx* iface)
172 dispex *This = impl_from_IDispatchEx(iface);
173 trace("AddRef\n");
175 return InterlockedIncrement(&This->refs);
178 static ULONG WINAPI dispex_Release(IDispatchEx* iface)
180 dispex *This = impl_from_IDispatchEx(iface);
181 ULONG refs = InterlockedDecrement(&This->refs);
182 trace("Release\n");
183 if(!refs)
185 HeapFree(GetProcessHeap(), 0, This);
187 return refs;
190 static HRESULT WINAPI dispex_GetTypeInfoCount(IDispatchEx* iface,
191 UINT *pctinfo)
193 trace("\n");
194 return E_NOTIMPL;
197 static HRESULT WINAPI dispex_GetTypeInfo(IDispatchEx* iface,
198 UINT iTInfo,
199 LCID lcid,
200 ITypeInfo **ppTInfo)
202 trace("\n");
203 return E_NOTIMPL;
206 static HRESULT WINAPI dispex_GetIDsOfNames(IDispatchEx* iface,
207 REFIID riid,
208 LPOLESTR *rgszNames,
209 UINT cNames,
210 LCID lcid,
211 DISPID *rgDispId)
213 trace("\n");
214 return E_NOTIMPL;
217 static HRESULT WINAPI dispex_Invoke(IDispatchEx* iface,
218 DISPID dispIdMember,
219 REFIID riid,
220 LCID lcid,
221 WORD wFlags,
222 DISPPARAMS *pDispParams,
223 VARIANT *pVarResult,
224 EXCEPINFO *pExcepInfo,
225 UINT *puArgErr)
227 trace("\n");
228 return E_NOTIMPL;
231 static HRESULT WINAPI dispex_GetDispID(IDispatchEx* iface,
232 BSTR bstrName,
233 DWORD grfdex,
234 DISPID *pid)
236 trace("\n");
237 return E_NOTIMPL;
240 static HRESULT WINAPI defer_fn(EXCEPINFO *except)
242 except->scode = E_OUTOFMEMORY;
243 return S_OK;
246 static HRESULT WINAPI dispex_InvokeEx(IDispatchEx* iface,
247 DISPID id,
248 LCID lcid,
249 WORD wFlags,
250 DISPPARAMS *pdp,
251 VARIANT *pvarRes,
252 EXCEPINFO *pei,
253 IServiceProvider *pspCaller)
255 if(id == 1)
257 ok(pdp->cArgs == 0, "got %d\n", pdp->cArgs);
258 ok(pei == NULL, "got non-NULL excepinfo\n");
259 ok(pvarRes == NULL, "got non-NULL result\n");
261 else if(id == 2)
263 ok(pdp->cArgs == 2, "got %d\n", pdp->cArgs);
264 ok(V_VT(&pdp->rgvarg[0]) == VT_INT, "got %04x\n", V_VT(&pdp->rgvarg[0]));
265 ok(V_VT(&pdp->rgvarg[1]) == (VT_INT | VT_BYREF), "got %04x\n", V_VT(&pdp->rgvarg[1]));
266 ok(*V_INTREF(&pdp->rgvarg[1]) == 0xbeef, "got %08x\n", *V_INTREF(&pdp->rgvarg[1]));
267 *V_INTREF(&pdp->rgvarg[1]) = 0xdead;
269 else if(id == 3)
271 ok(pdp->cArgs == 2, "got %d\n", pdp->cArgs);
272 ok(V_VT(&pdp->rgvarg[0]) == VT_INT, "got %04x\n", V_VT(&pdp->rgvarg[0]));
273 ok(V_VT(&pdp->rgvarg[1]) == (VT_INT | VT_BYREF), "got %04x\n", V_VT(&pdp->rgvarg[1]));
274 V_VT(&pdp->rgvarg[0]) = VT_I4;
276 else if(id == 4)
278 ok(wFlags == 0xf, "got %04x\n", wFlags);
280 else if(id == 5)
282 if(pei) pei->pfnDeferredFillIn = defer_fn;
283 return DISP_E_EXCEPTION;
285 return S_OK;
288 static HRESULT WINAPI dispex_DeleteMemberByName(IDispatchEx* iface,
289 BSTR bstrName,
290 DWORD grfdex)
292 trace("\n");
293 return E_NOTIMPL;
296 static HRESULT WINAPI dispex_DeleteMemberByDispID(IDispatchEx* iface, DISPID id)
298 trace("\n");
299 return E_NOTIMPL;
302 static HRESULT WINAPI dispex_GetMemberProperties(IDispatchEx* iface, DISPID id,
303 DWORD grfdexFetch, DWORD *pgrfdex)
305 trace("\n");
306 return E_NOTIMPL;
309 static HRESULT WINAPI dispex_GetMemberName(IDispatchEx* iface,
310 DISPID id, BSTR *pbstrName)
312 trace("\n");
313 return E_NOTIMPL;
316 static HRESULT WINAPI dispex_GetNextDispID(IDispatchEx* iface,
317 DWORD grfdex,
318 DISPID id,
319 DISPID *pid)
321 trace("\n");
322 return E_NOTIMPL;
325 static HRESULT WINAPI dispex_GetNameSpaceParent(IDispatchEx* iface,
326 IUnknown **ppunk)
328 trace("\n");
329 return E_NOTIMPL;
332 static const IDispatchExVtbl dispex_vtable =
334 dispex_QueryInterface,
335 dispex_AddRef,
336 dispex_Release,
337 dispex_GetTypeInfoCount,
338 dispex_GetTypeInfo,
339 dispex_GetIDsOfNames,
340 dispex_Invoke,
341 dispex_GetDispID,
342 dispex_InvokeEx,
343 dispex_DeleteMemberByName,
344 dispex_DeleteMemberByDispID,
345 dispex_GetMemberProperties,
346 dispex_GetMemberName,
347 dispex_GetNextDispID,
348 dispex_GetNameSpaceParent
351 static IDispatchEx *dispex_create(void)
353 dispex *This;
355 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
356 if (!This) return NULL;
357 This->IDispatchEx_iface.lpVtbl = &dispex_vtable;
358 This->refs = 1;
359 return (IDispatchEx *)This;
362 static void test_dispex(void)
364 HRESULT hr;
365 IStream *stream;
366 DWORD tid;
367 HANDLE thread;
368 static const LARGE_INTEGER zero;
369 IDispatchEx *dispex = dispex_create();
370 DISPPARAMS params;
371 VARIANTARG args[10];
372 INT i;
373 EXCEPINFO excepinfo;
375 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
376 ok(hr == S_OK, "got %08x\n", hr);
377 tid = start_host_object(stream, &IID_IDispatchEx, (IUnknown *)dispex, MSHLFLAGS_NORMAL, &thread);
378 IDispatchEx_Release(dispex);
379 if(tid == 0)
381 IStream_Release(stream);
382 return;
385 IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
386 hr = CoUnmarshalInterface(stream, &IID_IDispatchEx, (void **)&dispex);
387 ok(hr == S_OK, "got %08x\n", hr);
388 IStream_Release(stream);
390 params.rgvarg = NULL;
391 params.rgdispidNamedArgs = NULL;
392 params.cArgs = 0;
393 params.cNamedArgs = 0;
394 hr = IDispatchEx_InvokeEx(dispex, 1, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);
395 ok(hr == S_OK, "got %08x\n", hr);
397 params.rgvarg = args;
398 params.rgdispidNamedArgs = NULL;
399 params.cArgs = 2;
400 params.cNamedArgs = 0;
401 V_VT(&args[0]) = VT_INT;
402 V_INT(&args[0]) = 0xcafe;
403 V_VT(&args[1]) = VT_INT | VT_BYREF;
404 V_INTREF(&args[1]) = &i;
405 i = 0xbeef;
406 hr = IDispatchEx_InvokeEx(dispex, 2, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);
407 ok(hr == S_OK, "got %08x\n", hr);
408 ok(i == 0xdead, "got %08x\n", i);
410 /* change one of the argument vts */
411 i = 0xbeef;
412 hr = IDispatchEx_InvokeEx(dispex, 3, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);
413 ok(hr == DISP_E_BADCALLEE, "got %08x\n", hr);
415 hr = IDispatchEx_InvokeEx(dispex, 4, LOCALE_SYSTEM_DEFAULT, 0xffff, &params, NULL, NULL, NULL);
416 ok(hr == S_OK, "got %08x\n", hr);
418 params.cArgs = 0;
419 hr = IDispatchEx_InvokeEx(dispex, 5, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);
420 ok(hr == DISP_E_EXCEPTION, "got %08x\n", hr);
421 hr = IDispatchEx_InvokeEx(dispex, 5, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &params, NULL, &excepinfo, NULL);
422 ok(hr == DISP_E_EXCEPTION, "got %08x\n", hr);
423 ok(excepinfo.scode == E_OUTOFMEMORY, "got scode %08x\n", excepinfo.scode);
424 ok(excepinfo.pfnDeferredFillIn == NULL, "got non-NULL pfnDeferredFillIn\n");
426 IDispatchEx_Release(dispex);
427 end_host_object(tid, thread);
430 START_TEST(marshal)
432 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
434 test_dispex();
436 CoUninitialize();