oleaut32/tests: Add tmarshal test.
[wine] / dlls / oleaut32 / tests / tmarshal.c
1 /*
2  * Copyright (C) 2005-2006 Robert Shearman for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  */
19
20 #define COBJMACROS
21
22 #include <windows.h>
23 #include <ocidl.h>
24 #include <stdio.h>
25
26 #include <wine/test.h>
27
28 #include "tmarshal.h"
29 #include "tmarshal_dispids.h"
30
31 #define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08lx\n", (unsigned long int)hr)
32
33 /* Debugging functions from wine/libs/wine/debug.c */
34
35 /* allocate some tmp string space */
36 /* FIXME: this is not 100% thread-safe */
37 static char *get_tmp_space( int size )
38 {
39     static char *list[32];
40     static long pos;
41     char *ret;
42     int idx;
43
44     idx = ++pos % (sizeof(list)/sizeof(list[0]));
45     if ((ret = realloc( list[idx], size ))) list[idx] = ret;
46     return ret;
47 }
48
49 /* default implementation of wine_dbgstr_wn */
50 static const char *default_dbgstr_wn( const WCHAR *str, int n )
51 {
52     char *dst, *res;
53
54     if (!HIWORD(str))
55     {
56         if (!str) return "(null)";
57         res = get_tmp_space( 6 );
58         sprintf( res, "#%04x", LOWORD(str) );
59         return res;
60     }
61     if (n == -1) n = lstrlenW(str);
62     if (n < 0) n = 0;
63     else if (n > 200) n = 200;
64     dst = res = get_tmp_space( n * 5 + 7 );
65     *dst++ = 'L';
66     *dst++ = '"';
67     while (n-- > 0)
68     {
69         WCHAR c = *str++;
70         switch (c)
71         {
72         case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
73         case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
74         case '\t': *dst++ = '\\'; *dst++ = 't'; break;
75         case '"':  *dst++ = '\\'; *dst++ = '"'; break;
76         case '\\': *dst++ = '\\'; *dst++ = '\\'; break;
77         default:
78             if (c >= ' ' && c <= 126)
79                 *dst++ = (char)c;
80             else
81             {
82                 *dst++ = '\\';
83                 sprintf(dst,"%04x",c);
84                 dst+=4;
85             }
86         }
87     }
88     *dst++ = '"';
89     if (*str)
90     {
91         *dst++ = '.';
92         *dst++ = '.';
93         *dst++ = '.';
94     }
95     *dst = 0;
96     return res;
97 }
98
99 const char *wine_dbgstr_wn( const WCHAR *s, int n )
100 {
101     return default_dbgstr_wn(s, n);
102 }
103
104 const char *wine_dbgstr_w( const WCHAR *s )
105 {
106     return default_dbgstr_wn( s, -1 );
107 }
108
109
110 #define RELEASEMARSHALDATA WM_USER
111
112 struct host_object_data
113 {
114     IStream *stream;
115     IID iid;
116     IUnknown *object;
117     MSHLFLAGS marshal_flags;
118     HANDLE marshal_event;
119     IMessageFilter *filter;
120 };
121
122 static DWORD CALLBACK host_object_proc(LPVOID p)
123 {
124     struct host_object_data *data = (struct host_object_data *)p;
125     HRESULT hr;
126     MSG msg;
127
128     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
129
130     if (data->filter)
131     {
132         IMessageFilter * prev_filter = NULL;
133         hr = CoRegisterMessageFilter(data->filter, &prev_filter);
134         if (prev_filter) IMessageFilter_Release(prev_filter);
135         ok_ole_success(hr, CoRegisterMessageFilter);
136     }
137
138     hr = CoMarshalInterface(data->stream, &data->iid, data->object, MSHCTX_INPROC, NULL, data->marshal_flags);
139     todo_wine
140     {
141         ok_ole_success(hr, CoMarshalInterface);
142     }
143
144     /* force the message queue to be created before signaling parent thread */
145     PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
146
147     SetEvent(data->marshal_event);
148
149     while (GetMessage(&msg, NULL, 0, 0))
150     {
151         if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA)
152         {
153             trace("releasing marshal data\n");
154             CoReleaseMarshalData(data->stream);
155             SetEvent((HANDLE)msg.lParam);
156         }
157         else
158             DispatchMessage(&msg);
159     }
160
161     HeapFree(GetProcessHeap(), 0, data);
162
163     CoUninitialize();
164
165     return hr;
166 }
167
168 static DWORD start_host_object2(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, IMessageFilter *filter, HANDLE *thread)
169 {
170     DWORD tid = 0;
171     HANDLE marshal_event = CreateEvent(NULL, FALSE, FALSE, NULL);
172     struct host_object_data *data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
173
174     data->stream = stream;
175     data->iid = *riid;
176     data->object = object;
177     data->marshal_flags = marshal_flags;
178     data->marshal_event = marshal_event;
179     data->filter = filter;
180
181     *thread = CreateThread(NULL, 0, host_object_proc, data, 0, &tid);
182
183     /* wait for marshaling to complete before returning */
184     WaitForSingleObject(marshal_event, INFINITE);
185     CloseHandle(marshal_event);
186
187     return tid;
188 }
189
190 static DWORD start_host_object(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, HANDLE *thread)
191 {
192     return start_host_object2(stream, riid, object, marshal_flags, NULL, thread);
193 }
194
195 #if 0 /* not used */
196 /* asks thread to release the marshal data because it has to be done by the
197  * same thread that marshaled the interface in the first place. */
198 static void release_host_object(DWORD tid)
199 {
200     HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
201     PostThreadMessage(tid, RELEASEMARSHALDATA, 0, (LPARAM)event);
202     WaitForSingleObject(event, INFINITE);
203     CloseHandle(event);
204 }
205 #endif
206
207 static void end_host_object(DWORD tid, HANDLE thread)
208 {
209     BOOL ret = PostThreadMessage(tid, WM_QUIT, 0, 0);
210     ok(ret, "PostThreadMessage failed with error %d\n", GetLastError());
211     /* be careful of races - don't return until hosting thread has terminated */
212     WaitForSingleObject(thread, INFINITE);
213     CloseHandle(thread);
214 }
215
216 typedef struct Widget
217 {
218     const IWidgetVtbl *lpVtbl;
219     LONG refs;
220     IUnknown *pDispatchUnknown;
221 } Widget;
222
223 HRESULT WINAPI Widget_QueryInterface(
224     IWidget *iface,
225     /* [in] */ REFIID riid,
226     /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
227 {
228     if (IsEqualIID(riid, &IID_IWidget) || IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch))
229     {
230         IWidget_AddRef(iface);
231         *ppvObject = iface;
232         return S_OK;
233     }
234     else
235     {
236         *ppvObject = NULL;
237         return E_NOINTERFACE;
238     }
239 }
240
241 ULONG WINAPI Widget_AddRef(
242     IWidget *iface)
243 {
244     Widget *This = (Widget *)iface;
245
246     return InterlockedIncrement(&This->refs);
247 }
248
249 ULONG WINAPI Widget_Release(
250     IWidget *iface)
251 {
252     Widget *This = (Widget *)iface;
253     ULONG refs = InterlockedDecrement(&This->refs);
254     if (!refs)
255     {
256         IUnknown_Release(This->pDispatchUnknown);
257         memset(This, 0xcc, sizeof(*This));
258         HeapFree(GetProcessHeap(), 0, This);
259         trace("Widget destroyed!\n");
260     }
261
262     return refs;
263 }
264
265 HRESULT WINAPI Widget_GetTypeInfoCount(
266     IWidget *iface,
267     /* [out] */ UINT __RPC_FAR *pctinfo)
268 {
269     Widget *This = (Widget *)iface;
270     IDispatch *pDispatch;
271     HRESULT hr = IUnknown_QueryInterface(This->pDispatchUnknown, &IID_IDispatch, (void **)&pDispatch);
272     if (SUCCEEDED(hr))
273     {
274         hr = IDispatch_GetTypeInfoCount(pDispatch, pctinfo);
275         IDispatch_Release(pDispatch);
276     }
277     return hr;
278 }
279
280 HRESULT WINAPI Widget_GetTypeInfo(
281     IWidget __RPC_FAR * iface,
282     /* [in] */ UINT iTInfo,
283     /* [in] */ LCID lcid,
284     /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo)
285 {
286     Widget *This = (Widget *)iface;
287     IDispatch *pDispatch;
288     HRESULT hr = IUnknown_QueryInterface(This->pDispatchUnknown, &IID_IDispatch, (void **)&pDispatch);
289     if (SUCCEEDED(hr))
290     {
291         hr = IDispatch_GetTypeInfo(pDispatch, iTInfo, lcid, ppTInfo);
292         IDispatch_Release(pDispatch);
293     }
294     return hr;
295 }
296
297 HRESULT WINAPI Widget_GetIDsOfNames(
298     IWidget __RPC_FAR * iface,
299     /* [in] */ REFIID riid,
300     /* [size_is][in] */ LPOLESTR __RPC_FAR *rgszNames,
301     /* [in] */ UINT cNames,
302     /* [in] */ LCID lcid,
303     /* [size_is][out] */ DISPID __RPC_FAR *rgDispId)
304 {
305     Widget *This = (Widget *)iface;
306     IDispatch *pDispatch;
307     HRESULT hr = IUnknown_QueryInterface(This->pDispatchUnknown, &IID_IDispatch, (void **)&pDispatch);
308     if (SUCCEEDED(hr))
309     {
310         hr = IDispatch_GetIDsOfNames(pDispatch, riid, rgszNames, cNames, lcid, rgDispId);
311         IDispatch_Release(pDispatch);
312     }
313     return hr;
314 }
315
316 HRESULT WINAPI Widget_Invoke(
317     IWidget __RPC_FAR * iface,
318     /* [in] */ DISPID dispIdMember,
319     /* [in] */ REFIID riid,
320     /* [in] */ LCID lcid,
321     /* [in] */ WORD wFlags,
322     /* [out][in] */ DISPPARAMS __RPC_FAR *pDispParams,
323     /* [out] */ VARIANT __RPC_FAR *pVarResult,
324     /* [out] */ EXCEPINFO __RPC_FAR *pExcepInfo,
325     /* [out] */ UINT __RPC_FAR *puArgErr)
326 {
327     Widget *This = (Widget *)iface;
328     IDispatch *pDispatch;
329     HRESULT hr = IUnknown_QueryInterface(This->pDispatchUnknown, &IID_IDispatch, (void **)&pDispatch);
330     if (SUCCEEDED(hr))
331     {
332         hr = IDispatch_Invoke(pDispatch, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
333         IDispatch_Release(pDispatch);
334     }
335     return hr;
336 }
337
338 HRESULT WINAPI Widget_put_Name(
339     IWidget __RPC_FAR * iface,
340     /* [in] */ BSTR name)
341 {
342     trace("put_Name(%s)\n", wine_dbgstr_w(name));
343     return S_OK;
344 }
345
346 HRESULT WINAPI Widget_get_Name(
347     IWidget __RPC_FAR * iface,
348     /* [out] */ BSTR __RPC_FAR *name)
349 {
350     static const WCHAR szCat[] = { 'C','a','t',0 };
351     trace("get_Name()\n");
352     *name = SysAllocString(szCat);
353     return S_OK;
354 }
355
356 HRESULT WINAPI Widget_DoSomething(
357     IWidget __RPC_FAR * iface,
358     /* [in] */ double number,
359     /* [out] */ BSTR *str1,
360     /* [defaultvalue][in] */ BSTR str2,
361     /* [optional][in] */ VARIANT __RPC_FAR *opt)
362 {
363     static const WCHAR szString[] = { 'S','t','r','i','n','g',0 };
364     trace("DoSomething()\n");
365
366     ok(number == 3.141, "number(%f) != 3.141\n", number);
367     ok(*str2 == '\0', "str2(%s) != \"\"\n", wine_dbgstr_w(str2));
368     ok(V_VT(opt) == VT_ERROR, "V_VT(opt) should be VT_ERROR instead of 0x%x\n", V_VT(opt));
369     ok(V_ERROR(opt) == DISP_E_PARAMNOTFOUND, "V_ERROR(opt) should be DISP_E_PARAMNOTFOUND instead of 0x%08x\n", V_ERROR(opt));
370     *str1 = SysAllocString(szString);
371
372     return S_FALSE;
373 }
374
375 HRESULT WINAPI Widget_get_State(
376     IWidget __RPC_FAR * iface,
377     /* [retval][out] */ STATE __RPC_FAR *state)
378 {
379     trace("get_State() = STATE_WIDGETIFIED\n");
380     *state = STATE_WIDGETIFIED;
381     return S_OK;
382 }
383
384 HRESULT WINAPI Widget_put_State(
385     IWidget __RPC_FAR * iface,
386     /* [in] */ STATE state)
387 {
388     trace("put_State(%d)\n", state);
389     return S_OK;
390 }
391
392 HRESULT WINAPI Widget_Map(
393     IWidget * iface,
394     BSTR bstrId,
395     BSTR *sValue)
396 {
397     trace("Map(%s, %p)\n", wine_dbgstr_w(bstrId), sValue);
398     *sValue = SysAllocString(bstrId);
399     return S_OK;
400 }
401
402 HRESULT WINAPI Widget_SetOleColor(
403     IWidget * iface,
404     OLE_COLOR val)
405 {
406     trace("SetOleColor(0x%x)\n", val);
407     return S_OK;
408 }
409
410 HRESULT WINAPI Widget_GetOleColor(
411     IWidget * iface,
412     OLE_COLOR *pVal)
413 {
414     trace("GetOleColor() = 0x8000000f\n");
415     *pVal = 0x8000000f;
416     return S_FALSE;
417 }
418
419 HRESULT WINAPI Widget_Clone(
420     IWidget *iface,
421     IWidget **ppVal)
422 {
423     trace("Clone()\n");
424     return Widget_QueryInterface(iface, &IID_IWidget, (void **)ppVal);
425 }
426
427 HRESULT WINAPI Widget_CloneDispatch(
428     IWidget *iface,
429     IDispatch **ppVal)
430 {
431     trace("CloneDispatch()\n");
432     return Widget_QueryInterface(iface, &IID_IWidget, (void **)ppVal);
433 }
434
435 HRESULT WINAPI Widget_CloneCoclass(
436     IWidget *iface,
437     ApplicationObject2 **ppVal)
438 {
439     trace("CloneDispatch()\n");
440     return S_OK;
441 }
442
443 HRESULT WINAPI Widget_Value(
444     IWidget __RPC_FAR * iface,
445     VARIANT *value,
446     VARIANT *retval)
447 {
448     trace("Value(%p, %p)\n", value, retval);
449     ok(V_VT(value) == VT_I2, "V_VT(value) was %d instead of VT_I2\n", V_VT(value));
450     ok(V_I2(value) == 1, "V_I2(value) was %d instead of 1\n", V_I2(value));
451     V_VT(retval) = VT_I2;
452     V_I2(retval) = 1234;
453     return S_OK;
454 }
455
456 HRESULT WINAPI Widget_Array(
457     IWidget * iface,
458     SAFEARRAY * values)
459 {
460     trace("Array(%p)\n", values);
461     return S_OK;
462 }
463
464 HRESULT WINAPI Widget_VariantArrayPtr(
465     IWidget * iface,
466     SAFEARRAY ** values)
467 {
468     trace("VariantArrayPtr(%p)\n", values);
469     return S_OK;
470 }
471
472 void WINAPI Widget_Variant(
473     IWidget __RPC_FAR * iface,
474     VARIANT var)
475 {
476     trace("Variant()\n");
477     ok(V_VT(&var) == VT_CY, "V_VT(&var) was %d\n", V_VT(&var));
478     ok(S(V_CY(&var)).Hi == 0xdababe, "V_CY(&var).Hi was 0x%x\n", S(V_CY(&var)).Hi);
479     ok(S(V_CY(&var)).Lo == 0xdeadbeef, "V_CY(&var).Lo was 0x%x\n", S(V_CY(&var)).Lo);
480 }
481
482 HRESULT WINAPI Widget_Error(
483     IWidget __RPC_FAR * iface)
484 {
485     trace("Error()\n");
486     return E_NOTIMPL;
487 }
488
489 static const struct IWidgetVtbl Widget_VTable =
490 {
491     Widget_QueryInterface,
492     Widget_AddRef,
493     Widget_Release,
494     Widget_GetTypeInfoCount,
495     Widget_GetTypeInfo,
496     Widget_GetIDsOfNames,
497     Widget_Invoke,
498     Widget_put_Name,
499     Widget_get_Name,
500     Widget_DoSomething,
501     Widget_get_State,
502     Widget_put_State,
503     Widget_Map,
504     Widget_SetOleColor,
505     Widget_GetOleColor,
506     Widget_Clone,
507     Widget_CloneDispatch,
508     Widget_CloneCoclass,
509     Widget_Value,
510     Widget_Array,
511     Widget_VariantArrayPtr,
512     Widget_Variant,
513     Widget_Error
514 };
515
516
517 typedef struct KindaEnum
518 {
519     const IKindaEnumWidgetVtbl *lpVtbl;
520     LONG refs;
521 } KindaEnum;
522
523 static HRESULT register_current_module_typelib(ITypeLib **typelib)
524 {
525     WCHAR path[MAX_PATH];
526     HRESULT hr;
527
528     GetModuleFileNameW(NULL, path, MAX_PATH);
529
530     hr = LoadTypeLib(path, typelib);
531     if (SUCCEEDED(hr))
532         hr = RegisterTypeLib(*typelib, path, NULL);
533     return hr;
534 }
535
536 static IWidget *Widget_Create(void)
537 {
538     Widget *This = (Widget *)HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
539     HRESULT hr;
540     ITypeLib *pTypeLib;
541
542     This->lpVtbl = &Widget_VTable;
543     This->refs = 1;
544
545     hr = LoadRegTypeLib(&LIBID_TestTypelib, 1, 0, LOCALE_NEUTRAL, &pTypeLib);
546     ok_ole_success(hr, LoadRegTypeLib);
547     if (hr == TYPE_E_LIBNOTREGISTERED)
548     {
549         hr = register_current_module_typelib(&pTypeLib);
550         ok_ole_success(hr, register_current_module_typelib);
551     }
552     if (SUCCEEDED(hr))
553     {
554         ITypeInfo *pTypeInfo;
555         hr = ITypeLib_GetTypeInfoOfGuid(pTypeLib, &IID_IWidget, &pTypeInfo);
556         ok_ole_success(hr, ITypeLib_GetTypeInfoOfGuid);
557         if (SUCCEEDED(hr))
558         {
559             This->pDispatchUnknown = NULL;
560             hr = CreateStdDispatch((IUnknown *)&This->lpVtbl, This, pTypeInfo, &This->pDispatchUnknown);
561             ok_ole_success(hr, CreateStdDispatch);
562             ITypeInfo_Release(pTypeInfo);
563         }
564     }
565
566     if (SUCCEEDED(hr))
567         return (IWidget *)&This->lpVtbl;
568     else
569     {
570         HeapFree(GetProcessHeap(), 0, This);
571         return NULL;
572     }
573 }
574
575 HRESULT WINAPI KindaEnum_QueryInterface(
576     IKindaEnumWidget *iface,
577     /* [in] */ REFIID riid,
578     /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
579 {
580     if (IsEqualIID(riid, &IID_IKindaEnumWidget) || IsEqualIID(riid, &IID_IUnknown))
581     {
582         IKindaEnumWidget_AddRef(iface);
583         *ppvObject = iface;
584         return S_OK;
585     }
586     else
587     {
588         *ppvObject = NULL;
589         return E_NOINTERFACE;
590     }
591 }
592
593 ULONG WINAPI KindaEnum_AddRef(
594     IKindaEnumWidget *iface)
595 {
596     KindaEnum *This = (KindaEnum *)iface;
597
598     return InterlockedIncrement(&This->refs);
599 }
600
601 ULONG WINAPI KindaEnum_Release(
602     IKindaEnumWidget *iface)
603 {
604     KindaEnum *This = (KindaEnum *)iface;
605     ULONG refs = InterlockedDecrement(&This->refs);
606     if (!refs)
607     {
608         memset(This, 0xcc, sizeof(*This));
609         HeapFree(GetProcessHeap(), 0, This);
610         trace("KindaEnumWidget destroyed!\n");
611     }
612
613     return refs;
614 }
615
616 HRESULT WINAPI KindaEnum_Next(
617     IKindaEnumWidget *iface,
618     /* [out] */ IWidget __RPC_FAR *__RPC_FAR *widget)
619 {
620     *widget = Widget_Create();
621     if (*widget)
622         return S_OK;
623     else
624         return E_OUTOFMEMORY;
625 }
626
627 HRESULT WINAPI KindaEnum_Count(
628     IKindaEnumWidget *iface,
629     /* [out] */ unsigned long __RPC_FAR *count)
630 {
631     return E_NOTIMPL;
632 }
633
634 HRESULT WINAPI KindaEnum_Reset(
635     IKindaEnumWidget *iface)
636 {
637     return E_NOTIMPL;
638 }
639
640 HRESULT WINAPI KindaEnum_Clone(
641     IKindaEnumWidget *iface,
642     /* [out] */ IKindaEnumWidget __RPC_FAR *__RPC_FAR *ppenum)
643 {
644     return E_NOTIMPL;
645 }
646
647 static const IKindaEnumWidgetVtbl KindaEnumWidget_VTable =
648 {
649     KindaEnum_QueryInterface,
650     KindaEnum_AddRef,
651     KindaEnum_Release,
652     KindaEnum_Next,
653     KindaEnum_Count,
654     KindaEnum_Reset,
655     KindaEnum_Clone
656 };
657
658 static IKindaEnumWidget *KindaEnumWidget_Create(void)
659 {
660     KindaEnum *This;
661     HRESULT hr;
662     ITypeLib *pTypeLib;
663
664     hr = LoadRegTypeLib(&LIBID_TestTypelib, 1, 0, LOCALE_NEUTRAL, &pTypeLib);
665     ok_ole_success(hr, LoadRegTypeLib);
666     if (hr == TYPE_E_LIBNOTREGISTERED)
667     {
668         hr = register_current_module_typelib(&pTypeLib);
669         ok_ole_success(hr, register_current_module_typelib);
670     }
671     if (SUCCEEDED(hr))
672         ITypeLib_Release(pTypeLib);
673
674     This = (KindaEnum *)HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
675     if (!This) return NULL;
676     This->lpVtbl = &KindaEnumWidget_VTable;
677     This->refs = 1;
678     return (IKindaEnumWidget *)This;
679 }
680
681 static HRESULT WINAPI NonOleAutomation_QueryInterface(INonOleAutomation *iface, REFIID riid, void **ppv)
682 {
683     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_INonOleAutomation))
684     {
685         *(INonOleAutomation **)ppv = iface;
686         return S_OK;
687     }
688     *ppv = NULL;
689     return E_NOINTERFACE;
690 }
691
692 static ULONG WINAPI NonOleAutomation_AddRef(INonOleAutomation *iface)
693 {
694     return 2;
695 }
696
697 static ULONG WINAPI NonOleAutomation_Release(INonOleAutomation *iface)
698 {
699     return 1;
700 }
701
702 static BSTR WINAPI NonOleAutomation_BstrRet(INonOleAutomation *iface)
703 {
704     static const WCHAR wszTestString[] = {'T','h','i','s',' ','i','s',' ','a',' ','t','e','s','t',' ','s','t','r','i','n','g',0};
705     return SysAllocString(wszTestString);
706 }
707
708 static INonOleAutomationVtbl NonOleAutomation_VTable =
709 {
710     NonOleAutomation_QueryInterface,
711     NonOleAutomation_AddRef,
712     NonOleAutomation_Release,
713     NonOleAutomation_BstrRet,
714 };
715
716 static INonOleAutomation NonOleAutomation = { &NonOleAutomation_VTable };
717
718 static ITypeInfo *NonOleAutomation_GetTypeInfo(void)
719 {
720     ITypeLib *pTypeLib;
721     HRESULT hr = LoadRegTypeLib(&LIBID_TestTypelib, 1, 0, LOCALE_NEUTRAL, &pTypeLib);
722     if (hr == TYPE_E_LIBNOTREGISTERED)
723     {
724         hr = register_current_module_typelib(&pTypeLib);
725         ok_ole_success(hr, register_current_module_typelib);
726     }
727     if (SUCCEEDED(hr))
728     {
729         ITypeInfo *pTypeInfo;
730         hr = ITypeLib_GetTypeInfoOfGuid(pTypeLib, &IID_INonOleAutomation, &pTypeInfo);
731         ok_ole_success(hr, ITypeLib_GetTypeInfoOfGuid);
732         return pTypeInfo;
733     }
734     return NULL;
735 }
736
737 static void test_typelibmarshal(void)
738 {
739     static const WCHAR szCat[] = { 'C','a','t',0 };
740     static const WCHAR szTestTest[] = { 'T','e','s','t','T','e','s','t',0 };
741     static WCHAR szSuperman[] = { 'S','u','p','e','r','m','a','n',0 };
742     HRESULT hr;
743     IKindaEnumWidget *pKEW = KindaEnumWidget_Create();
744     IWidget *pWidget;
745     IStream *pStream;
746     IDispatch *pDispatch;
747     static const LARGE_INTEGER ullZero;
748     EXCEPINFO excepinfo;
749     VARIANT varresult;
750     DISPID dispidNamed = DISPID_PROPERTYPUT;
751     DISPPARAMS dispparams;
752     VARIANTARG vararg[4];
753     STATE the_state;
754     HANDLE thread;
755     DWORD tid;
756     BSTR bstr;
757     ITypeInfo *pTypeInfo;
758
759     ok(pKEW != NULL, "Widget creation failed\n");
760
761     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
762     ok_ole_success(hr, CreateStreamOnHGlobal);
763     tid = start_host_object(pStream, &IID_IKindaEnumWidget, (IUnknown *)pKEW, MSHLFLAGS_NORMAL, &thread);
764
765     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
766     hr = CoUnmarshalInterface(pStream, &IID_IKindaEnumWidget, (void **)&pKEW);
767     todo_wine
768     {
769         ok_ole_success(hr, CoUnmarshalInterface);
770     }
771     IStream_Release(pStream);
772
773     hr = IKindaEnumWidget_Next(pKEW, &pWidget);
774     ok_ole_success(hr, IKindaEnumWidget_Next);
775
776     IKindaEnumWidget_Release(pKEW);
777
778     hr = IWidget_QueryInterface(pWidget, &IID_IDispatch, (void **)&pDispatch);
779
780     /* call put_Name */
781     VariantInit(&vararg[0]);
782     dispparams.cNamedArgs = 1;
783     dispparams.rgdispidNamedArgs = &dispidNamed;
784     dispparams.cArgs = 1;
785     dispparams.rgvarg = vararg;
786     VariantInit(&varresult);
787     hr = IDispatch_Invoke(pDispatch, DISPID_TM_NAME, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
788     ok_ole_success(hr, IDispatch_Invoke);
789     todo_wine
790     {
791         ok(excepinfo.wCode == 0x0 && excepinfo.scode == S_OK,
792             "EXCEPINFO differs from expected: wCode = 0x%x, scode = 0x%08x\n",
793             excepinfo.wCode, excepinfo.scode);
794     }
795     VariantClear(&varresult);
796
797     /* call put_Name (direct) */
798     bstr = SysAllocString(szSuperman);
799     hr = IWidget_put_Name(pWidget, bstr);
800     ok_ole_success(hr, IWidget_put_Name);
801     SysFreeString(bstr);
802
803     /* call get_Name */
804     dispparams.cNamedArgs = 0;
805     dispparams.rgdispidNamedArgs = NULL;
806     dispparams.cArgs = 0;
807     dispparams.rgvarg = NULL;
808     VariantInit(&varresult);
809     hr = IDispatch_Invoke(pDispatch, DISPID_TM_NAME, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
810     ok_ole_success(hr, IDispatch_Invoke);
811     todo_wine
812     {
813         ok(excepinfo.wCode == 0x0 && excepinfo.scode == S_OK,
814             "EXCEPINFO differs from expected: wCode = 0x%x, scode = 0x%08x\n",
815             excepinfo.wCode, excepinfo.scode);
816     }
817     trace("Name = %s\n", wine_dbgstr_w(V_BSTR(&varresult)));
818     VariantClear(&varresult);
819
820     /* call get_Name (direct) */
821     bstr = NULL;
822     hr = IWidget_get_Name(pWidget, &bstr);
823     ok_ole_success(hr, IWidget_get_Name);
824     ok(!lstrcmpW(bstr, szCat), "IWidget_get_Name should have returned string \"Cat\" instead of %s\n", wine_dbgstr_w(bstr));
825     SysFreeString(bstr);
826
827     /* call DoSomething */
828     VariantInit(&vararg[0]);
829     VariantInit(&vararg[1]);
830     V_VT(&vararg[1]) = VT_R8;
831     V_R8(&vararg[1]) = 3.141;
832     dispparams.cNamedArgs = 0;
833     dispparams.cArgs = 2;
834     dispparams.rgdispidNamedArgs = NULL;
835     dispparams.rgvarg = vararg;
836     VariantInit(&varresult);
837     hr = IDispatch_Invoke(pDispatch, DISPID_TM_DOSOMETHING, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
838     ok_ole_success(hr, IDispatch_Invoke);
839     ok(V_VT(&varresult) == VT_EMPTY, "varresult should be VT_EMPTY\n");
840     VariantClear(&varresult);
841
842     /* call get_State */
843     dispparams.cNamedArgs = 0;
844     dispparams.cArgs = 0;
845     dispparams.rgdispidNamedArgs = NULL;
846     dispparams.rgvarg = NULL;
847     hr = IDispatch_Invoke(pDispatch, DISPID_TM_STATE, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
848     ok_ole_success(hr, IDispatch_Invoke);
849     ok((V_VT(&varresult) == VT_I4) && (V_I4(&varresult) == STATE_WIDGETIFIED), "Return val mismatch\n");
850
851     /* call get_State (direct) */
852     hr = IWidget_get_State(pWidget, &the_state);
853     ok_ole_success(hr, IWidget_get_state);
854     ok(the_state == STATE_WIDGETIFIED, "should have returned WIDGET_WIDGETIFIED instead of %d\n", the_state);
855
856     /* call put_State */
857     the_state = STATE_WIDGETIFIED;
858     VariantInit(&vararg[0]);
859     V_VT(&vararg[0]) = VT_BYREF|VT_I4;
860     V_I4REF(&vararg[0]) = (int *)&the_state;
861     dispparams.cNamedArgs = 1;
862     dispparams.cArgs = 1;
863     dispparams.rgdispidNamedArgs = &dispidNamed;
864     dispparams.rgvarg = vararg;
865     hr = IDispatch_Invoke(pDispatch, DISPID_TM_STATE, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
866     ok_ole_success(hr, IDispatch_Invoke);
867
868     /* call Map */
869     bstr = SysAllocString(szTestTest);
870     VariantInit(&vararg[0]);
871     V_VT(&vararg[0]) = VT_BYREF|VT_BSTR;
872     V_BSTRREF(&vararg[0]) = &bstr;
873     dispparams.cNamedArgs = 0;
874     dispparams.cArgs = 1;
875     dispparams.rgdispidNamedArgs = NULL;
876     dispparams.rgvarg = vararg;
877     VariantInit(&varresult);
878     hr = IDispatch_Invoke(pDispatch, DISPID_TM_MAP, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
879     ok_ole_success(hr, IDispatch_Invoke);
880     ok(V_VT(&varresult) == VT_BSTR, "Return value should be of type BSTR instead of %d\n", V_VT(&varresult));
881     ok(!lstrcmpW(V_BSTR(&varresult), szTestTest), "Return value should have been \"TestTest\" instead of %s\n", wine_dbgstr_w(V_BSTR(&varresult)));
882     VariantClear(&varresult);
883
884     /* call SetOleColor with large negative VT_I4 param */
885     VariantInit(&vararg[0]);
886     V_VT(&vararg[0]) = VT_I4;
887     V_I4(&vararg[0]) = 0x80000005;
888     dispparams.cNamedArgs = 0;
889     dispparams.cArgs = 1;
890     dispparams.rgdispidNamedArgs = NULL;
891     dispparams.rgvarg = vararg;
892     hr = IDispatch_Invoke(pDispatch, DISPID_TM_SETOLECOLOR, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, NULL, &excepinfo, NULL);
893     ok_ole_success(hr, IDispatch_Invoke);
894
895     /* call GetOleColor */
896     dispparams.cNamedArgs = 0;
897     dispparams.cArgs = 0;
898     dispparams.rgdispidNamedArgs = NULL;
899     dispparams.rgvarg = NULL;
900     VariantInit(&varresult);
901     hr = IDispatch_Invoke(pDispatch, DISPID_TM_GETOLECOLOR, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
902     ok_ole_success(hr, IDispatch_Invoke);
903     VariantClear(&varresult);
904
905     /* call Clone */
906     dispparams.cNamedArgs = 0;
907     dispparams.cArgs = 0;
908     dispparams.rgdispidNamedArgs = NULL;
909     dispparams.rgvarg = NULL;
910     VariantInit(&varresult);
911     hr = IDispatch_Invoke(pDispatch, DISPID_TM_CLONE, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
912     ok_ole_success(hr, IDispatch_Invoke);
913     VariantClear(&varresult);
914
915     /* call CloneDispatch with automatic value getting */
916     V_VT(&vararg[0]) = VT_I2;
917     V_I2(&vararg[0]) = 1;
918     dispparams.cNamedArgs = 0;
919     dispparams.rgdispidNamedArgs = NULL;
920     dispparams.cArgs = 1;
921     dispparams.rgvarg = vararg;
922     VariantInit(&varresult);
923     hr = IDispatch_Invoke(pDispatch, DISPID_TM_CLONEDISPATCH, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
924     ok_ole_success(hr, IDispatch_Invoke);
925     todo_wine
926     {
927         ok(excepinfo.wCode == 0x0 && excepinfo.scode == S_OK,
928             "EXCEPINFO differs from expected: wCode = 0x%x, scode = 0x%08x\n",
929             excepinfo.wCode, excepinfo.scode);
930
931         ok(V_VT(&varresult) == VT_I2, "V_VT(&varresult) was %d instead of VT_I2\n", V_VT(&varresult));
932         ok(V_I2(&varresult) == 1234, "V_I2(&varresult) was %d instead of 1234\n", V_I2(&varresult));
933     }
934     VariantClear(&varresult);
935
936     /* call Value with a VT_VARIANT|VT_BYREF type */
937     V_VT(&vararg[0]) = VT_VARIANT|VT_BYREF;
938     V_VARIANTREF(&vararg[0]) = &vararg[1];
939     V_VT(&vararg[1]) = VT_I2;
940     V_I2(&vararg[1]) = 1;
941     dispparams.cNamedArgs = 0;
942     dispparams.rgdispidNamedArgs = NULL;
943     dispparams.cArgs = 1;
944     dispparams.rgvarg = vararg;
945     VariantInit(&varresult);
946     hr = IDispatch_Invoke(pDispatch, DISPID_VALUE, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
947     todo_wine
948     {
949         ok_ole_success(hr, IDispatch_Invoke);
950
951         ok(excepinfo.wCode == 0x0 && excepinfo.scode == S_OK,
952         "EXCEPINFO differs from expected: wCode = 0x%x, scode = 0x%08x\n",
953             excepinfo.wCode, excepinfo.scode);
954
955         ok(V_VT(&varresult) == VT_I2, "V_VT(&varresult) was %d instead of VT_I2\n", V_VT(&varresult));
956         ok(V_I2(&varresult) == 1234, "V_I2(&varresult) was %d instead of 1234\n", V_I2(&varresult));
957     }
958     VariantClear(&varresult);
959
960     /* call Variant - exercises variant copying in ITypeInfo::Invoke and
961      * handling of void return types */
962     /* use a big type to ensure that the variant was properly copied into the
963      * destination function's args */
964     V_VT(&vararg[0]) = VT_CY;
965     S(V_CY(&vararg[0])).Hi = 0xdababe;
966     S(V_CY(&vararg[0])).Lo = 0xdeadbeef;
967     dispparams.cNamedArgs = 0;
968     dispparams.cArgs = 1;
969     dispparams.rgdispidNamedArgs = NULL;
970     dispparams.rgvarg = vararg;
971     VariantInit(&varresult);
972     hr = IDispatch_Invoke(pDispatch, DISPID_TM_VARIANT, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, NULL, NULL, NULL);
973     ok_ole_success(hr, IDispatch_Invoke);
974     VariantClear(&varresult);
975
976     /* call Error */
977     dispparams.cNamedArgs = 0;
978     dispparams.cArgs = 0;
979     dispparams.rgdispidNamedArgs = NULL;
980     dispparams.rgvarg = NULL;
981     VariantInit(&varresult);
982     hr = IDispatch_Invoke(pDispatch, DISPID_TM_ERROR, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, NULL, &excepinfo, NULL);
983     ok(hr == DISP_E_EXCEPTION, "IDispatch_Invoke should have returned DISP_E_EXCEPTION instead of 0x%08x\n", hr);
984     todo_wine
985     {
986         ok(excepinfo.wCode == 0x0 && excepinfo.scode == E_NOTIMPL,
987             "EXCEPINFO differs from expected: wCode = 0x%x, scode = 0x%08x\n",
988             excepinfo.wCode, excepinfo.scode);
989     }
990     VariantClear(&varresult);
991
992     /* call BstrRet */
993     pTypeInfo = NonOleAutomation_GetTypeInfo();
994     dispparams.cNamedArgs = 0;
995     dispparams.cArgs = 0;
996     dispparams.rgdispidNamedArgs = NULL;
997     dispparams.rgvarg = NULL;
998     VariantInit(&varresult);
999     hr = ITypeInfo_Invoke(pTypeInfo, &NonOleAutomation, DISPID_NOA_BSTRRET, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
1000     ok_ole_success(hr, ITypeInfo_Invoke);
1001     todo_wine
1002     {
1003         ok(V_VT(&varresult) == VT_BSTR, "V_VT(&varresult) should be VT_BSTR instead of %d\n", V_VT(&varresult));
1004     }
1005     ok(V_BSTR(&varresult) != NULL, "V_BSTR(&varresult) should not be NULL\n");
1006
1007     VariantClear(&varresult);
1008     ITypeInfo_Release(pTypeInfo);
1009
1010     /* tests call put_Name without named arg */
1011     VariantInit(&vararg[0]);
1012     dispparams.cNamedArgs = 0;
1013     dispparams.rgdispidNamedArgs = NULL;
1014     dispparams.cArgs = 1;
1015     dispparams.rgvarg = vararg;
1016     VariantInit(&varresult);
1017     hr = IDispatch_Invoke(pDispatch, DISPID_TM_NAME, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
1018     todo_wine
1019     {
1020         ok(hr == DISP_E_PARAMNOTFOUND, "IDispatch_Invoke should have returned DISP_E_PARAMNOTFOUND instead of 0x%08x\n", hr);
1021     }
1022     VariantClear(&varresult);
1023
1024     /* tests param type that cannot be coerced */
1025     VariantInit(&vararg[0]);
1026     V_VT(&vararg[0]) = VT_UNKNOWN;
1027     V_UNKNOWN(&vararg[0]) = NULL;
1028     dispparams.cNamedArgs = 1;
1029     dispparams.rgdispidNamedArgs = &dispidNamed;
1030     dispparams.cArgs = 1;
1031     dispparams.rgvarg = vararg;
1032     VariantInit(&varresult);
1033     hr = IDispatch_Invoke(pDispatch, DISPID_TM_NAME, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
1034     ok(hr == DISP_E_TYPEMISMATCH, "IDispatch_Invoke should have returned DISP_E_TYPEMISMATCH instead of 0x%08x\n", hr);
1035     VariantClear(&varresult);
1036
1037     /* tests bad param type */
1038     VariantInit(&vararg[0]);
1039     V_VT(&vararg[0]) = VT_CLSID;
1040     V_BYREF(&vararg[0]) = NULL;
1041     dispparams.cNamedArgs = 1;
1042     dispparams.rgdispidNamedArgs = &dispidNamed;
1043     dispparams.cArgs = 1;
1044     dispparams.rgvarg = vararg;
1045     VariantInit(&varresult);
1046     hr = IDispatch_Invoke(pDispatch, DISPID_TM_NAME, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
1047     ok(hr == DISP_E_BADVARTYPE, "IDispatch_Invoke should have returned DISP_E_BADVARTYPE instead of 0x%08x\n", hr);
1048     VariantClear(&varresult);
1049
1050     /* tests too small param count */
1051     dispparams.cNamedArgs = 0;
1052     dispparams.rgdispidNamedArgs = NULL;
1053     dispparams.cArgs = 0;
1054     dispparams.rgvarg = NULL;
1055     VariantInit(&varresult);
1056     hr = IDispatch_Invoke(pDispatch, DISPID_TM_DOSOMETHING, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
1057     ok(hr == DISP_E_BADPARAMCOUNT, "IDispatch_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
1058     VariantClear(&varresult);
1059
1060     /* tests propget function with large param count */
1061     VariantInit(&vararg[0]);
1062     V_VT(&vararg[0]) = VT_BSTR;
1063     V_BSTR(&vararg[0]) = NULL;
1064     V_VT(&vararg[1]) = VT_I4;
1065     V_I4(&vararg[1]) = 1;
1066     dispparams.cNamedArgs = 0;
1067     dispparams.cArgs = 2;
1068     dispparams.rgdispidNamedArgs = NULL;
1069     dispparams.rgvarg = vararg;
1070     hr = IDispatch_Invoke(pDispatch, DISPID_TM_STATE, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
1071     todo_wine
1072     {
1073         ok(hr == DISP_E_NOTACOLLECTION, "IDispatch_Invoke should have returned DISP_E_NOTACOLLECTION instead of 0x%08x\n", hr);
1074     }
1075
1076     IDispatch_Release(pDispatch);
1077     IWidget_Release(pWidget);
1078
1079     trace("calling end_host_object\n");
1080     end_host_object(tid, thread);
1081 }
1082
1083 static void test_DispCallFunc(void)
1084 {
1085     static const WCHAR szEmpty[] = { 0 };
1086     VARTYPE rgvt[] = { VT_R8, VT_BSTR, VT_BSTR, VT_VARIANT|VT_BYREF };
1087     VARIANTARG vararg[4];
1088     VARIANTARG varref;
1089     VARIANTARG *rgpvarg[4] = { &vararg[0], &vararg[1], &vararg[2], &vararg[3] };
1090     VARIANTARG varresult;
1091     HRESULT hr;
1092     IWidget *pWidget = Widget_Create();
1093     V_VT(&vararg[0]) = VT_R8;
1094     V_R8(&vararg[0]) = 3.141;
1095     V_VT(&vararg[1]) = VT_BSTR;
1096     V_BSTR(&vararg[1]) = SysAllocString(szEmpty);
1097     V_VT(&vararg[2]) = VT_BSTR;
1098     V_BSTR(&vararg[2]) = SysAllocString(szEmpty);
1099     V_VT(&vararg[3]) = VT_VARIANT|VT_BYREF;
1100     V_VARIANTREF(&vararg[3]) = &varref;
1101     V_VT(&varref) = VT_ERROR;
1102     V_ERROR(&varref) = DISP_E_PARAMNOTFOUND;
1103     VariantInit(&varresult);
1104     hr = DispCallFunc(pWidget, 36, CC_STDCALL, VT_UI4, 4, rgvt, rgpvarg, &varresult);
1105     ok_ole_success(hr, DispCallFunc);
1106     VariantClear(&varresult);
1107 }
1108
1109 START_TEST(tmarshal)
1110 {
1111     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1112
1113     test_typelibmarshal();
1114     test_DispCallFunc();
1115
1116     CoUninitialize();
1117 }