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
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
43 MSHLFLAGS marshal_flags
;
46 IMessageFilter
*filter
;
49 static DWORD CALLBACK
host_object_proc(LPVOID p
)
51 struct host_object_data
*data
= p
;
55 CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);
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
);
71 SetEvent(data
->marshal_event
);
74 win_skip("IDispatchEx marshaller not available.\n");
75 SetEvent(data
->error_event
);
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
);
88 DispatchMessage(&msg
);
91 HeapFree(GetProcessHeap(), 0, data
);
98 static DWORD
start_host_object2(IStream
*stream
, REFIID riid
, IUnknown
*object
, MSHLFLAGS marshal_flags
, IMessageFilter
*filter
, HANDLE
*thread
)
102 struct host_object_data
*data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*data
));
104 data
->stream
= stream
;
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
;
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
);
143 IDispatchEx IDispatchEx_iface
;
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
);
166 return E_NOINTERFACE
;
170 static ULONG WINAPI
dispex_AddRef(IDispatchEx
* iface
)
172 dispex
*This
= impl_from_IDispatchEx(iface
);
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
);
185 HeapFree(GetProcessHeap(), 0, This
);
190 static HRESULT WINAPI
dispex_GetTypeInfoCount(IDispatchEx
* iface
,
197 static HRESULT WINAPI
dispex_GetTypeInfo(IDispatchEx
* iface
,
206 static HRESULT WINAPI
dispex_GetIDsOfNames(IDispatchEx
* iface
,
217 static HRESULT WINAPI
dispex_Invoke(IDispatchEx
* iface
,
222 DISPPARAMS
*pDispParams
,
224 EXCEPINFO
*pExcepInfo
,
231 static HRESULT WINAPI
dispex_GetDispID(IDispatchEx
* iface
,
240 static HRESULT WINAPI
defer_fn(EXCEPINFO
*except
)
242 except
->scode
= E_OUTOFMEMORY
;
246 static HRESULT WINAPI
dispex_InvokeEx(IDispatchEx
* iface
,
253 IServiceProvider
*pspCaller
)
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");
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;
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
;
278 ok(wFlags
== 0xf, "got %04x\n", wFlags
);
282 if(pei
) pei
->pfnDeferredFillIn
= defer_fn
;
283 return DISP_E_EXCEPTION
;
288 static HRESULT WINAPI
dispex_DeleteMemberByName(IDispatchEx
* iface
,
296 static HRESULT WINAPI
dispex_DeleteMemberByDispID(IDispatchEx
* iface
, DISPID id
)
302 static HRESULT WINAPI
dispex_GetMemberProperties(IDispatchEx
* iface
, DISPID id
,
303 DWORD grfdexFetch
, DWORD
*pgrfdex
)
309 static HRESULT WINAPI
dispex_GetMemberName(IDispatchEx
* iface
,
310 DISPID id
, BSTR
*pbstrName
)
316 static HRESULT WINAPI
dispex_GetNextDispID(IDispatchEx
* iface
,
325 static HRESULT WINAPI
dispex_GetNameSpaceParent(IDispatchEx
* iface
,
332 static const IDispatchExVtbl dispex_vtable
=
334 dispex_QueryInterface
,
337 dispex_GetTypeInfoCount
,
339 dispex_GetIDsOfNames
,
343 dispex_DeleteMemberByName
,
344 dispex_DeleteMemberByDispID
,
345 dispex_GetMemberProperties
,
346 dispex_GetMemberName
,
347 dispex_GetNextDispID
,
348 dispex_GetNameSpaceParent
351 static IDispatchEx
*dispex_create(void)
355 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
356 if (!This
) return NULL
;
357 This
->IDispatchEx_iface
.lpVtbl
= &dispex_vtable
;
359 return (IDispatchEx
*)This
;
362 static void test_dispex(void)
368 static const LARGE_INTEGER zero
;
369 IDispatchEx
*dispex
= dispex_create();
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
);
381 IStream_Release(stream
);
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
;
393 params
.cNamedArgs
= 0;
394 hr
= IDispatchEx_InvokeEx(dispex
, 1, LOCALE_SYSTEM_DEFAULT
, DISPATCH_METHOD
, ¶ms
, NULL
, NULL
, NULL
);
395 ok(hr
== S_OK
, "got %08x\n", hr
);
397 params
.rgvarg
= args
;
398 params
.rgdispidNamedArgs
= NULL
;
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
;
406 hr
= IDispatchEx_InvokeEx(dispex
, 2, LOCALE_SYSTEM_DEFAULT
, DISPATCH_METHOD
, ¶ms
, 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 */
412 hr
= IDispatchEx_InvokeEx(dispex
, 3, LOCALE_SYSTEM_DEFAULT
, DISPATCH_METHOD
, ¶ms
, NULL
, NULL
, NULL
);
413 ok(hr
== DISP_E_BADCALLEE
, "got %08x\n", hr
);
415 hr
= IDispatchEx_InvokeEx(dispex
, 4, LOCALE_SYSTEM_DEFAULT
, 0xffff, ¶ms
, NULL
, NULL
, NULL
);
416 ok(hr
== S_OK
, "got %08x\n", hr
);
419 hr
= IDispatchEx_InvokeEx(dispex
, 5, LOCALE_SYSTEM_DEFAULT
, DISPATCH_METHOD
, ¶ms
, NULL
, NULL
, NULL
);
420 ok(hr
== DISP_E_EXCEPTION
, "got %08x\n", hr
);
421 hr
= IDispatchEx_InvokeEx(dispex
, 5, LOCALE_SYSTEM_DEFAULT
, DISPATCH_METHOD
, ¶ms
, 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
);
432 CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);