1 /*
2  * Dispatch test
3  *
4  * Copyright 2009 James Hawkins
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 COBJMACROS
22 #define CONST_VTABLE
23 
24 #include <wine/test.h>
25 #include <windef.h>
26 #include <winbase.h>
27 #include <oaidl.h>
28 
29 static const WCHAR szSunshine[] = {'S','u','n','s','h','i','n','e',0};
30 
31 /* Temporary storage for ok_bstr. */
32 static CHAR temp_str[MAX_PATH];
33 
34 #define ok_bstr(bstr, expected, format) \
35     do { \
36     WideCharToMultiByte(CP_ACP, 0, bstr, -1, temp_str, MAX_PATH, NULL, NULL); \
37     if (lstrcmpA(temp_str, expected) != 0) \
38         ok(0, format, expected, temp_str); \
39     } while(0);
40 
41 #define INIT_DISPPARAMS(dp, args, named_args, num_args, num_named_args) \
42   dp.rgvarg = args; \
43   dp.rgdispidNamedArgs = named_args; \
44   dp.cArgs = num_args; \
45   dp.cNamedArgs = num_named_args; \
46 
47 /* Initializes vararg with three values:
48  *  VT_I2 - 42
49  *  VT_I4 - 1234567890
50  *  VT_BSTR - "Sunshine"
51  */
52 #define INIT_VARARG(vararg) \
53   VariantInit(&vararg[0]); \
54   V_VT(&vararg[0]) = VT_I2; \
55   V_I2(&vararg[0]) = 42; \
56   VariantInit(&vararg[1]); \
57   V_VT(&vararg[1]) = VT_I4; \
58   V_I4(&vararg[1]) = 1234567890; \
59   VariantInit(&vararg[2]); \
60   V_VT(&vararg[2]) = VT_BSTR; \
61   V_BSTR(&vararg[2]) = SysAllocString(szSunshine);
62 
63 /* Clears the vararg. */
64 #define CLEAR_VARARG(vararg) \
65   VariantClear(&vararg[0]); \
66   VariantClear(&vararg[1]); \
67   VariantClear(&vararg[2]);
68 
69 static void test_DispGetParam(void)
70 {
71     HRESULT hr;
72     DISPPARAMS dispparams;
73     VARIANTARG vararg[3];
74     VARIANT result;
75     unsigned int err_index;
76 
77     VariantInit(&result);
78 
79     /* DispGetParam crashes on Windows if pdispparams is NULL. */
80 
81     /* pdispparams has zero parameters. */
82     INIT_DISPPARAMS(dispparams, NULL, NULL, 0, 0);
83     VariantInit(&result);
84     err_index = 0xdeadbeef;
85     hr = DispGetParam(&dispparams, 0, VT_I2, &result, &err_index);
86     ok(hr == DISP_E_PARAMNOTFOUND,
87        "Expected DISP_E_PARAMNOTFOUND, got %08x\n", hr);
88     ok(V_VT(&result) == VT_EMPTY,
89        "Expected VT_EMPTY, got %08x\n", V_VT(&result));
90     ok(err_index == 0xdeadbeef,
91        "Expected err_index to be unchanged, got %d\n", err_index);
92 
93     /* pdispparams has zero parameters, position is invalid. */
94     INIT_DISPPARAMS(dispparams, NULL, NULL, 0, 0);
95     VariantInit(&result);
96     err_index = 0xdeadbeef;
97     hr = DispGetParam(&dispparams, 1, VT_I2, &result, &err_index);
98     ok(hr == DISP_E_PARAMNOTFOUND,
99        "Expected DISP_E_PARAMNOTFOUND, got %08x\n", hr);
100     ok(V_VT(&result) == VT_EMPTY,
101        "Expected VT_EMPTY, got %08x\n", V_VT(&result));
102     ok(err_index == 0xdeadbeef,
103        "Expected err_index to be unchanged, got %d\n", err_index);
104 
105     /* pdispparams has zero parameters, pvarResult is NULL. */
106     INIT_DISPPARAMS(dispparams, NULL, NULL, 0, 0);
107     err_index = 0xdeadbeef;
108     hr = DispGetParam(&dispparams, 0, VT_I2, NULL, &err_index);
109     ok(hr == DISP_E_PARAMNOTFOUND,
110        "Expected DISP_E_PARAMNOTFOUND, got %08x\n", hr);
111     ok(err_index == 0xdeadbeef,
112        "Expected err_index to be unchanged, got %d\n", err_index);
113 
114     /* pdispparams has zero parameters, puArgErr is NULL. */
115     INIT_DISPPARAMS(dispparams, NULL, NULL, 0, 0);
116     VariantInit(&result);
117     hr = DispGetParam(&dispparams, 0, VT_I2, &result, NULL);
118     ok(hr == DISP_E_PARAMNOTFOUND,
119        "Expected DISP_E_PARAMNOTFOUND, got %08x\n", hr);
120     ok(V_VT(&result) == VT_EMPTY,
121        "Expected VT_EMPTY, got %08x\n", V_VT(&result));
122 
123     /* pdispparams.cArgs is 1, yet pdispparams.rgvarg is NULL. */
124     INIT_DISPPARAMS(dispparams, NULL, NULL, 1, 0);
125     VariantInit(&result);
126     err_index = 0xdeadbeef;
127     hr = DispGetParam(&dispparams, 0, VT_I2, &result, &err_index);
128     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
129     ok(V_VT(&result) == VT_EMPTY,
130        "Expected VT_EMPTY, got %08x\n", V_VT(&result));
131     ok(err_index == 0, "Expected 0, got %d\n", err_index);
132 
133     /* pdispparams.cNamedArgs is 1, yet pdispparams.rgdispidNamedArgs is NULL.
134      *
135      * This crashes on Windows.
136      */
137 
138     /* {42, 1234567890, "Sunshine"} */
139     INIT_VARARG(vararg);
140 
141     /* Get the first param.  position is end-based, so 2 is the first parameter
142      * of 3 parameters.
143      */
144     INIT_DISPPARAMS(dispparams, vararg, NULL, 3, 0);
145     VariantInit(&result);
146     err_index = 0xdeadbeef;
147     hr = DispGetParam(&dispparams, 2, VT_I2, &result, &err_index);
148     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
149     ok(V_VT(&result) == VT_I2, "Expected VT_I2, got %08x\n", V_VT(&result));
150     ok(V_I2(&result) == 42, "Expected 42, got %d\n", V_I2(&result));
151     ok(err_index == 0xdeadbeef,
152        "Expected err_index to be unchanged, got %d\n", err_index);
153 
154     /* Get the second param. */
155     INIT_DISPPARAMS(dispparams, vararg, NULL, 3, 0);
156     VariantInit(&result);
157     err_index = 0xdeadbeef;
158     hr = DispGetParam(&dispparams, 1, VT_I4, &result, &err_index);
159     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
160     ok(V_VT(&result) == VT_I4, "Expected VT_I4, got %08x\n", V_VT(&result));
161     ok(V_I4(&result) == 1234567890,
162        "Expected 1234567890, got %d\n", V_I4(&result));
163     ok(err_index == 0xdeadbeef,
164        "Expected err_index to be unchanged, got %d\n", err_index);
165 
166     /* Get the third param. */
167     INIT_DISPPARAMS(dispparams, vararg, NULL, 3, 0);
168     VariantInit(&result);
169     err_index = 0xdeadbeef;
170     hr = DispGetParam(&dispparams, 0, VT_BSTR, &result, &err_index);
171     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
172     ok(V_VT(&result) == VT_BSTR, "Expected VT_BSTR, got %08x\n", V_VT(&result));
173     ok_bstr(V_BSTR(&result), "Sunshine", "Expected %s, got %s\n");
174     ok(err_index == 0xdeadbeef,
175        "Expected err_index to be unchanged, got %d\n", err_index);
176     VariantClear(&result);
177 
178     /* position is out of range. */
179     INIT_DISPPARAMS(dispparams, vararg, NULL, 3, 0);
180     VariantInit(&result);
181     err_index = 0xdeadbeef;
182     hr = DispGetParam(&dispparams, 3, VT_I2, &result, &err_index);
183     ok(hr == DISP_E_PARAMNOTFOUND,
184        "Expected DISP_E_PARAMNOTFOUND, got %08x\n", hr);
185     ok(V_VT(&result) == VT_EMPTY,
186        "Expected VT_EMPTY, got %08x\n", V_VT(&result));
187     ok(err_index == 0xdeadbeef,
188        "Expected err_index to be unchanged, got %d\n", err_index);
189 
190     /* pvarResult is NULL. */
191     INIT_DISPPARAMS(dispparams, vararg, NULL, 3, 0);
192     err_index = 0xdeadbeef;
193     hr = DispGetParam(&dispparams, 2, VT_I2, NULL, &err_index);
194     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
195     ok(err_index == 0, "Expected 0, got %d\n", err_index);
196 
197     /* puArgErr is NULL. */
198     INIT_DISPPARAMS(dispparams, vararg, NULL, 3, 0);
199     VariantInit(&result);
200     hr = DispGetParam(&dispparams, 2, VT_I2, &result, NULL);
201     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
202     ok(V_VT(&result) == VT_I2, "Expected VT_I2, got %08x\n", V_VT(&result));
203     ok(V_I2(&result) == 42, "Expected 42, got %d\n", V_I2(&result));
204 
205     /* Coerce the first param to VT_I4. */
206     INIT_DISPPARAMS(dispparams, vararg, NULL, 3, 0);
207     VariantInit(&result);
208     err_index = 0xdeadbeef;
209     hr = DispGetParam(&dispparams, 2, VT_I4, &result, &err_index);
210     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
211     ok(V_VT(&result) == VT_I4, "Expected VT_I4, got %08x\n", V_VT(&result));
212     ok(V_I4(&result) == 42, "Expected 42, got %d\n", V_I4(&result));
213     ok(err_index == 0xdeadbeef,
214        "Expected err_index to be unchanged, got %d\n", err_index);
215 
216     /* Coerce the first param to VT_BSTR. */
217     INIT_DISPPARAMS(dispparams, vararg, NULL, 3, 0);
218     VariantInit(&result);
219     err_index = 0xdeadbeef;
220     hr = DispGetParam(&dispparams, 2, VT_BSTR, &result, &err_index);
221     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
222     ok(V_VT(&result) == VT_BSTR, "Expected VT_BSTR, got %08x\n", V_VT(&result));
223     ok_bstr(V_BSTR(&result), "42", "Expected %s, got %s\n");
224     ok(err_index == 0xdeadbeef,
225        "Expected err_index to be unchanged, got %d\n", err_index);
226     VariantClear(&result);
227 
228     /* Coerce the second (VT_I4) param to VT_I2. */
229     INIT_DISPPARAMS(dispparams, vararg, NULL, 3, 0);
230     VariantInit(&result);
231     err_index = 0xdeadbeef;
232     hr = DispGetParam(&dispparams, 1, VT_I2, &result, &err_index);
233     ok(hr == DISP_E_OVERFLOW, "Expected DISP_E_OVERFLOW, got %08x\n", hr);
234     ok(V_VT(&result) == VT_EMPTY,
235        "Expected VT_EMPTY, got %08x\n", V_VT(&result));
236     ok(err_index == 1, "Expected 1, got %d\n", err_index);
237 
238     /* Coerce the third (VT_BSTR) param to VT_I2. */
239     INIT_DISPPARAMS(dispparams, vararg, NULL, 3, 0);
240     VariantInit(&result);
241     err_index = 0xdeadbeef;
242     hr = DispGetParam(&dispparams, 0, VT_I2, &result, &err_index);
243     ok(hr == DISP_E_TYPEMISMATCH,
244        "Expected DISP_E_TYPEMISMATCH, got %08x\n", hr);
245     ok(V_VT(&result) == VT_EMPTY,
246        "Expected VT_EMPTY, got %08x\n", V_VT(&result));
247     ok(err_index == 2, "Expected 2, got %d\n", err_index);
248 
249     /* Coerce the first parameter to an invalid type. */
250     INIT_DISPPARAMS(dispparams, vararg, NULL, 3, 0);
251     VariantInit(&result);
252     err_index = 0xdeadbeef;
253     hr = DispGetParam(&dispparams, 2, VT_ILLEGAL, &result, &err_index);
254     ok(hr == DISP_E_BADVARTYPE, "Expected DISP_E_BADVARTYPE, got %08x\n", hr);
255     ok(V_VT(&result) == VT_EMPTY,
256        "Expected VT_EMPTY, got %08x\n", V_VT(&result));
257     ok(err_index == 0, "Expected 0, got %d\n", err_index);
258 
259     CLEAR_VARARG(vararg);
260 
261     /* Coerce the first parameter, which is of type VT_EMPTY, to VT_BSTR. */
262     VariantInit(&vararg[0]);
263     INIT_DISPPARAMS(dispparams, vararg, NULL, 1, 0);
264     VariantInit(&result);
265     err_index = 0xdeadbeef;
266     hr = DispGetParam(&dispparams, 0, VT_BSTR, &result, &err_index);
267     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
268     ok(V_VT(&result) == VT_BSTR, "Expected VT_BSTR, got %08x\n", V_VT(&result));
269     ok(err_index == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", err_index);
270     VariantClear(&result);
271 }
272 
273 static HRESULT WINAPI unk_QI(IUnknown *iface, REFIID riid, void **obj)
274 {
275     if (IsEqualIID(riid, &IID_IUnknown))
276     {
277         *obj = iface;
278         return S_OK;
279     }
280     else
281     {
282         *obj = NULL;
283         return E_NOINTERFACE;
284     }
285 }
286 
287 static ULONG WINAPI unk_AddRef(IUnknown *iface)
288 {
289     return 2;
290 }
291 
292 static ULONG WINAPI unk_Release(IUnknown *iface)
293 {
294     return 1;
295 }
296 
297 static const IUnknownVtbl unkvtbl =
298 {
299     unk_QI,
300     unk_AddRef,
301     unk_Release
302 };
303 
304 static IUnknown test_unk = { &unkvtbl };
305 
306 static void test_CreateStdDispatch(void)
307 {
308     static const WCHAR stdole2W[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
309     ITypeLib *tl;
310     ITypeInfo *ti;
311     IUnknown *unk;
312     HRESULT hr;
313 
314     hr = CreateStdDispatch(NULL, NULL, NULL, NULL);
315     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
316 
317     hr = CreateStdDispatch(NULL, NULL, NULL, &unk);
318     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
319 
320     hr = LoadTypeLib(stdole2W, &tl);
321     ok(hr == S_OK, "got %08x\n", hr);
322     hr = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IUnknown, &ti);
323     ok(hr == S_OK, "got %08x\n", hr);
324     ITypeLib_Release(tl);
325 
326     hr = CreateStdDispatch(NULL, &test_unk, NULL, &unk);
327     ok(hr == E_INVALIDARG, "got %08x\n", hr);
328 
329     hr = CreateStdDispatch(NULL, NULL, ti, &unk);
330     ok(hr == E_INVALIDARG, "got %08x\n", hr);
331 
332     hr = CreateStdDispatch(NULL, &test_unk, ti, &unk);
333     ok(hr == S_OK, "got %08x\n", hr);
334     IUnknown_Release(unk);
335 
336     ITypeInfo_Release(ti);
337 }
338 
339 START_TEST(dispatch)
340 {
341     test_DispGetParam();
342     test_CreateStdDispatch();
343 }
344