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