1 /*
2  * Copyright 2011 Jacek Caban 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #define WIN32_NO_STATUS
20 #define _INC_WINDOWS
21 #define COBJMACROS
22 #define CONST_VTABLE
23 
24 #include <windef.h>
25 #include <winbase.h>
26 #include <winreg.h>
27 #include <initguid.h>
28 #include <dispex.h>
29 #include <wshom.h>
30 #include <wine/test.h>
31 
32 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
33 
34 #define EXPECT_HR(hr,hr_exp) \
35     ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
36 
37 #define test_provideclassinfo(a, b) _test_provideclassinfo((IDispatch*)a, b, __LINE__)
38 static void _test_provideclassinfo(IDispatch *disp, const GUID *guid, int line)
39 {
40     IProvideClassInfo *classinfo;
41     TYPEATTR *attr;
42     ITypeInfo *ti;
43     HRESULT hr;
44 
45     hr = IDispatch_QueryInterface(disp, &IID_IProvideClassInfo, (void **)&classinfo);
46     ok_(__FILE__,line) (hr == S_OK, "Failed to get IProvideClassInfo, %#x.\n", hr);
47 
48     hr = IProvideClassInfo_GetClassInfo(classinfo, &ti);
49     ok_(__FILE__,line) (hr == S_OK, "GetClassInfo() failed, %#x.\n", hr);
50 
51     hr = ITypeInfo_GetTypeAttr(ti, &attr);
52     ok_(__FILE__,line) (hr == S_OK, "GetTypeAttr() failed, %#x.\n", hr);
53 
54     ok_(__FILE__,line) (IsEqualGUID(&attr->guid, guid), "Unexpected typeinfo %s, expected %s\n", wine_dbgstr_guid(&attr->guid),
55         wine_dbgstr_guid(guid));
56 
57     IProvideClassInfo_Release(classinfo);
58     ITypeInfo_ReleaseTypeAttr(ti, attr);
59     ITypeInfo_Release(ti);
60 }
61 
62 static void test_wshshell(void)
63 {
64     static const WCHAR notepadW[] = {'n','o','t','e','p','a','d','.','e','x','e',0};
65     static const WCHAR desktopW[] = {'D','e','s','k','t','o','p',0};
66     static const WCHAR lnk1W[] = {'f','i','l','e','.','l','n','k',0};
67     static const WCHAR pathW[] = {'%','P','A','T','H','%',0};
68     static const WCHAR sysW[] = {'S','Y','S','T','E','M',0};
69     static const WCHAR path2W[] = {'P','A','T','H',0};
70     static const WCHAR dummydirW[] = {'d','e','a','d','p','a','r','r','o','t',0};
71     static const WCHAR emptyW[] = {'e','m','p','t','y',0};
72     IWshEnvironment *env;
73     IWshExec *shexec;
74     IWshShell3 *sh3;
75     IDispatchEx *dispex;
76     IWshCollection *coll;
77     IDispatch *disp, *shortcut;
78     IUnknown *shell, *unk;
79     IFolderCollection *folders;
80     IWshShortcut *shcut;
81     ITypeInfo *ti;
82     HRESULT hr;
83     TYPEATTR *tattr;
84     DISPPARAMS dp;
85     EXCEPINFO ei;
86     VARIANT arg, res, arg2;
87     BSTR str, ret;
88     DWORD retval;
89     UINT err;
90 
91     hr = CoCreateInstance(&CLSID_WshShell, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
92             &IID_IDispatch, (void**)&disp);
93     ok(hr == S_OK, "got 0x%08x\n", hr);
94 
95     hr = IDispatch_QueryInterface(disp, &IID_IWshShell3, (void**)&shell);
96     EXPECT_HR(hr, S_OK);
97     test_provideclassinfo(disp, &IID_IWshShell3);
98 
99     hr = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
100     EXPECT_HR(hr, E_NOINTERFACE);
101     IDispatch_Release(disp);
102 
103     hr = IUnknown_QueryInterface(shell, &IID_IWshShell3, (void**)&sh3);
104     EXPECT_HR(hr, S_OK);
105 
106     hr = IWshShell3_QueryInterface(sh3, &IID_IObjectWithSite, (void**)&unk);
107     ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
108 
109     hr = IWshShell3_QueryInterface(sh3, &IID_IWshShell, (void**)&unk);
110     ok(hr == S_OK, "got 0x%08x\n", hr);
111     IUnknown_Release(unk);
112 
113     hr = IWshShell3_QueryInterface(sh3, &IID_IWshShell2, (void**)&unk);
114     ok(hr == S_OK, "got 0x%08x\n", hr);
115     IUnknown_Release(unk);
116 
117     hr = IWshShell3_get_SpecialFolders(sh3, &coll);
118     EXPECT_HR(hr, S_OK);
119     test_provideclassinfo(coll, &IID_IWshCollection);
120 
121     hr = IWshCollection_QueryInterface(coll, &IID_IFolderCollection, (void**)&folders);
122     EXPECT_HR(hr, E_NOINTERFACE);
123 
124     hr = IWshCollection_QueryInterface(coll, &IID_IDispatch, (void**)&disp);
125     EXPECT_HR(hr, S_OK);
126 
127     hr = IDispatch_GetTypeInfo(disp, 0, 0, &ti);
128     EXPECT_HR(hr, S_OK);
129 
130     hr = ITypeInfo_GetTypeAttr(ti, &tattr);
131     EXPECT_HR(hr, S_OK);
132     ok(IsEqualIID(&tattr->guid, &IID_IWshCollection), "got wrong type guid\n");
133     ITypeInfo_ReleaseTypeAttr(ti, tattr);
134 
135     /* try to call Item() with normal IDispatch procedure */
136     str = SysAllocString(desktopW);
137     V_VT(&arg) = VT_BSTR;
138     V_BSTR(&arg) = str;
139     dp.rgvarg = &arg;
140     dp.rgdispidNamedArgs = NULL;
141     dp.cArgs = 1;
142     dp.cNamedArgs = 0;
143     hr = IDispatch_Invoke(disp, DISPID_VALUE, &IID_NULL, 1033, DISPATCH_PROPERTYGET, &dp, &res, &ei, &err);
144     EXPECT_HR(hr, DISP_E_MEMBERNOTFOUND);
145 
146     /* try Item() directly, it returns directory path apparently */
147     V_VT(&res) = VT_EMPTY;
148     hr = IWshCollection_Item(coll, &arg, &res);
149     EXPECT_HR(hr, S_OK);
150     ok(V_VT(&res) == VT_BSTR, "got res type %d\n", V_VT(&res));
151     SysFreeString(str);
152     VariantClear(&res);
153 
154     /* CreateShortcut() */
155     str = SysAllocString(lnk1W);
156     hr = IWshShell3_CreateShortcut(sh3, str, &shortcut);
157     EXPECT_HR(hr, S_OK);
158     SysFreeString(str);
159     hr = IDispatch_QueryInterface(shortcut, &IID_IWshShortcut, (void**)&shcut);
160     EXPECT_HR(hr, S_OK);
161     test_provideclassinfo(shortcut, &IID_IWshShortcut);
162 
163     hr = IWshShortcut_get_Arguments(shcut, NULL);
164     ok(hr == E_POINTER, "got 0x%08x\n", hr);
165 
166     hr = IWshShortcut_get_IconLocation(shcut, NULL);
167     ok(hr == E_POINTER, "got 0x%08x\n", hr);
168 
169     IWshShortcut_Release(shcut);
170     IDispatch_Release(shortcut);
171 
172     /* ExpandEnvironmentStrings */
173     hr = IWshShell3_ExpandEnvironmentStrings(sh3, NULL, NULL);
174     ok(hr == E_POINTER, "got 0x%08x\n", hr);
175 
176     str = SysAllocString(pathW);
177     hr = IWshShell3_ExpandEnvironmentStrings(sh3, str, NULL);
178     ok(hr == E_POINTER, "got 0x%08x\n", hr);
179     SysFreeString(str);
180 
181     V_VT(&arg) = VT_BSTR;
182     V_BSTR(&arg) = SysAllocString(sysW);
183     hr = IWshShell3_get_Environment(sh3, &arg, &env);
184     ok(hr == S_OK, "got 0x%08x\n", hr);
185     VariantClear(&arg);
186 
187     hr = IWshEnvironment_get_Item(env, NULL, NULL);
188     ok(hr == E_POINTER, "got 0x%08x\n", hr);
189     test_provideclassinfo(env, &IID_IWshEnvironment);
190 
191     ret = (BSTR)0x1;
192     hr = IWshEnvironment_get_Item(env, NULL, &ret);
193     ok(hr == S_OK, "got 0x%08x\n", hr);
194     ok(ret && !*ret, "got %p\n", ret);
195     SysFreeString(ret);
196 
197     /* invalid var name */
198     str = SysAllocString(lnk1W);
199     hr = IWshEnvironment_get_Item(env, str, NULL);
200     ok(hr == E_POINTER, "got 0x%08x\n", hr);
201 
202     ret = NULL;
203     hr = IWshEnvironment_get_Item(env, str, &ret);
204     ok(hr == S_OK, "got 0x%08x\n", hr);
205     ok(ret && *ret == 0, "got %s\n", wine_dbgstr_w(ret));
206     SysFreeString(ret);
207     SysFreeString(str);
208 
209     /* valid name */
210     str = SysAllocString(path2W);
211     hr = IWshEnvironment_get_Item(env, str, &ret);
212     ok(hr == S_OK, "got 0x%08x\n", hr);
213     ok(ret && *ret != 0, "got %s\n", wine_dbgstr_w(ret));
214     SysFreeString(ret);
215     SysFreeString(str);
216 
217     IWshEnvironment_Release(env);
218 
219     V_VT(&arg) = VT_I2;
220     V_I2(&arg) = 0;
221     V_VT(&arg2) = VT_ERROR;
222     V_ERROR(&arg2) = DISP_E_PARAMNOTFOUND;
223 
224     str = SysAllocString(notepadW);
225     hr = IWshShell3_Run(sh3, str, &arg, &arg2, NULL);
226     ok(hr == E_POINTER, "got 0x%08x\n", hr);
227 
228     retval = 10;
229     hr = IWshShell3_Run(sh3, str, NULL, &arg2, &retval);
230     ok(hr == E_POINTER, "got 0x%08x\n", hr);
231     ok(retval == 10, "got %u\n", retval);
232 
233     retval = 10;
234     hr = IWshShell3_Run(sh3, str, &arg, NULL, &retval);
235     ok(hr == E_POINTER, "got 0x%08x\n", hr);
236     ok(retval == 10, "got %u\n", retval);
237 
238     retval = 10;
239     V_VT(&arg2) = VT_ERROR;
240     V_ERROR(&arg2) = 0;
241     hr = IWshShell3_Run(sh3, str, &arg, &arg2, &retval);
242     ok(hr == DISP_E_TYPEMISMATCH, "got 0x%08x\n", hr);
243     ok(retval == 10, "got %u\n", retval);
244 
245     SysFreeString(str);
246 
247     /* current directory */
248     if (0) /* crashes on native */
249         hr = IWshShell3_get_CurrentDirectory(sh3, NULL);
250 
251     str = NULL;
252     hr = IWshShell3_get_CurrentDirectory(sh3, &str);
253     ok(hr == S_OK, "got 0x%08x\n", hr);
254     ok(str && str[0] != 0, "got empty string\n");
255     SysFreeString(str);
256 
257     hr = IWshShell3_put_CurrentDirectory(sh3, NULL);
258     ok(hr == E_INVALIDARG ||
259        broken(hr == HRESULT_FROM_WIN32(ERROR_NOACCESS)), "got 0x%08x\n", hr);
260 
261     str = SysAllocString(emptyW);
262     hr = IWshShell3_put_CurrentDirectory(sh3, str);
263     ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got 0x%08x\n", hr);
264     SysFreeString(str);
265 
266     str = SysAllocString(dummydirW);
267     hr = IWshShell3_put_CurrentDirectory(sh3, str);
268     ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got 0x%08x\n", hr);
269     SysFreeString(str);
270 
271     /* Exec */
272     hr = IWshShell3_Exec(sh3, NULL, NULL);
273     ok(hr == E_POINTER, "got 0x%08x\n", hr);
274 
275     hr = IWshShell3_Exec(sh3, NULL, &shexec);
276     ok(hr == DISP_E_EXCEPTION, "got 0x%08x\n", hr);
277 
278     str = SysAllocString(emptyW);
279     hr = IWshShell3_Exec(sh3, str, &shexec);
280     ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got 0x%08x\n", hr);
281     SysFreeString(str);
282 
283     IWshCollection_Release(coll);
284     IDispatch_Release(disp);
285     IWshShell3_Release(sh3);
286     IUnknown_Release(shell);
287 }
288 
289 /* delete key and all its subkeys */
290 static DWORD delete_key(HKEY hkey)
291 {
292     char name[MAX_PATH];
293     DWORD ret;
294 
295     while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name)))) {
296         HKEY tmp;
297         if (!(ret = RegOpenKeyExA(hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp))) {
298             ret = delete_key(tmp);
299             RegCloseKey(tmp);
300         }
301         if (ret) break;
302     }
303     if (ret != ERROR_NO_MORE_ITEMS) return ret;
304     RegDeleteKeyA(hkey, "");
305     return 0;
306 }
307 
308 static void test_registry(void)
309 {
310     static const WCHAR keypathW[] = {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R','\\',
311         'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t','\\',0};
312     static const WCHAR regsz2W[] = {'r','e','g','s','z','2',0};
313     static const WCHAR regszW[] = {'r','e','g','s','z',0};
314     static const WCHAR regdwordW[] = {'r','e','g','d','w','o','r','d',0};
315     static const WCHAR regbinaryW[] = {'r','e','g','b','i','n','a','r','y',0};
316     static const WCHAR regmultiszW[] = {'r','e','g','m','u','l','t','i','s','z',0};
317 
318     static const WCHAR regsz1W[] = {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R','\\',
319         'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t','\\','r','e','g','s','z','1',0};
320     static const WCHAR foobarW[] = {'f','o','o','b','a','r',0};
321     static const WCHAR fooW[] = {'f','o','o',0};
322     static const WCHAR brokenW[] = {'H','K','E','Y','_','b','r','o','k','e','n','_','k','e','y',0};
323     static const WCHAR broken2W[] = {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R','a',0};
324     WCHAR pathW[MAX_PATH];
325     DWORD dwvalue, type;
326     VARIANT value, v;
327     IWshShell3 *sh3;
328     VARTYPE vartype;
329     LONG bound;
330     HRESULT hr;
331     BSTR name;
332     HKEY root;
333     LONG ret;
334     UINT dim;
335 
336     hr = CoCreateInstance(&CLSID_WshShell, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
337             &IID_IWshShell3, (void**)&sh3);
338     ok(hr == S_OK, "got 0x%08x\n", hr);
339 
340     /* RegRead() */
341     V_VT(&value) = VT_I2;
342     hr = IWshShell3_RegRead(sh3, NULL, &value);
343     ok(hr == E_POINTER, "got 0x%08x\n", hr);
344     ok(V_VT(&value) == VT_I2, "got %d\n", V_VT(&value));
345 
346     name = SysAllocString(brokenW);
347     hr = IWshShell3_RegRead(sh3, name, NULL);
348     ok(hr == E_POINTER, "got 0x%08x\n", hr);
349     V_VT(&value) = VT_I2;
350     hr = IWshShell3_RegRead(sh3, name, &value);
351     ok(hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "got 0x%08x\n", hr);
352     ok(V_VT(&value) == VT_I2, "got %d\n", V_VT(&value));
353     SysFreeString(name);
354 
355     name = SysAllocString(broken2W);
356     V_VT(&value) = VT_I2;
357     hr = IWshShell3_RegRead(sh3, name, &value);
358     ok(hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "got 0x%08x\n", hr);
359     ok(V_VT(&value) == VT_I2, "got %d\n", V_VT(&value));
360     SysFreeString(name);
361 
362     ret = RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &root);
363     ok(ret == 0, "got %d\n", ret);
364 
365     ret = RegSetValueExA(root, "regsz", 0, REG_SZ, (const BYTE*)"foobar", 7);
366     ok(ret == 0, "got %d\n", ret);
367 
368     ret = RegSetValueExA(root, "regsz2", 0, REG_SZ, (const BYTE*)"foobar\0f", 9);
369     ok(ret == 0, "got %d\n", ret);
370 
371     ret = RegSetValueExA(root, "regmultisz", 0, REG_MULTI_SZ, (const BYTE*)"foo\0bar\0", 9);
372     ok(ret == 0, "got %d\n", ret);
373 
374     dwvalue = 10;
375     ret = RegSetValueExA(root, "regdword", 0, REG_DWORD, (const BYTE*)&dwvalue, sizeof(dwvalue));
376     ok(ret == 0, "got %d\n", ret);
377 
378     dwvalue = 11;
379     ret = RegSetValueExA(root, "regbinary", 0, REG_BINARY, (const BYTE*)&dwvalue, sizeof(dwvalue));
380     ok(ret == 0, "got %d\n", ret);
381 
382     /* REG_SZ */
383     lstrcpyW(pathW, keypathW);
384     lstrcatW(pathW, regszW);
385     name = SysAllocString(pathW);
386     VariantInit(&value);
387     hr = IWshShell3_RegRead(sh3, name, &value);
388     ok(hr == S_OK, "got 0x%08x\n", hr);
389     ok(V_VT(&value) == VT_BSTR, "got %d\n", V_VT(&value));
390     ok(!lstrcmpW(V_BSTR(&value), foobarW), "got %s\n", wine_dbgstr_w(V_BSTR(&value)));
391     VariantClear(&value);
392     SysFreeString(name);
393 
394     /* REG_SZ with embedded NULL */
395     lstrcpyW(pathW, keypathW);
396     lstrcatW(pathW, regsz2W);
397     name = SysAllocString(pathW);
398     VariantInit(&value);
399     hr = IWshShell3_RegRead(sh3, name, &value);
400     ok(hr == S_OK, "got 0x%08x\n", hr);
401     ok(V_VT(&value) == VT_BSTR, "got %d\n", V_VT(&value));
402     ok(SysStringLen(V_BSTR(&value)) == 6, "len %d\n", SysStringLen(V_BSTR(&value)));
403     VariantClear(&value);
404     SysFreeString(name);
405 
406     /* REG_DWORD */
407     lstrcpyW(pathW, keypathW);
408     lstrcatW(pathW, regdwordW);
409     name = SysAllocString(pathW);
410     VariantInit(&value);
411     hr = IWshShell3_RegRead(sh3, name, &value);
412     ok(hr == S_OK, "got 0x%08x\n", hr);
413     ok(V_VT(&value) == VT_I4, "got %d\n", V_VT(&value));
414     ok(V_I4(&value) == 10, "got %d\n", V_I4(&value));
415     SysFreeString(name);
416 
417     /* REG_BINARY */
418     lstrcpyW(pathW, keypathW);
419     lstrcatW(pathW, regbinaryW);
420     name = SysAllocString(pathW);
421     VariantInit(&value);
422     hr = IWshShell3_RegRead(sh3, name, &value);
423     ok(hr == S_OK, "got 0x%08x\n", hr);
424     ok(V_VT(&value) == (VT_ARRAY|VT_VARIANT), "got 0x%x\n", V_VT(&value));
425     dim = SafeArrayGetDim(V_ARRAY(&value));
426     ok(dim == 1, "got %u\n", dim);
427 
428     hr = SafeArrayGetLBound(V_ARRAY(&value), 1, &bound);
429     ok(hr == S_OK, "got 0x%08x\n", hr);
430     ok(bound == 0, "got %u\n", bound);
431 
432     hr = SafeArrayGetUBound(V_ARRAY(&value), 1, &bound);
433     ok(hr == S_OK, "got 0x%08x\n", hr);
434     ok(bound == 3, "got %u\n", bound);
435 
436     hr = SafeArrayGetVartype(V_ARRAY(&value), &vartype);
437     ok(hr == S_OK, "got 0x%08x\n", hr);
438     ok(vartype == VT_VARIANT, "got %d\n", vartype);
439 
440     bound = 0;
441     hr = SafeArrayGetElement(V_ARRAY(&value), &bound, &v);
442     ok(hr == S_OK, "got 0x%08x\n", hr);
443     ok(V_VT(&v) == VT_UI1, "got %d\n", V_VT(&v));
444     ok(V_UI1(&v) == 11, "got %u\n", V_UI1(&v));
445     VariantClear(&v);
446     VariantClear(&value);
447     SysFreeString(name);
448 
449     /* REG_MULTI_SZ */
450     lstrcpyW(pathW, keypathW);
451     lstrcatW(pathW, regmultiszW);
452     name = SysAllocString(pathW);
453     VariantInit(&value);
454     hr = IWshShell3_RegRead(sh3, name, &value);
455     ok(hr == S_OK, "got 0x%08x\n", hr);
456     ok(V_VT(&value) == (VT_ARRAY|VT_VARIANT), "got 0x%x\n", V_VT(&value));
457     SysFreeString(name);
458 
459     dim = SafeArrayGetDim(V_ARRAY(&value));
460     ok(dim == 1, "got %u\n", dim);
461 
462     hr = SafeArrayGetLBound(V_ARRAY(&value), 1, &bound);
463     ok(hr == S_OK, "got 0x%08x\n", hr);
464     ok(bound == 0, "got %u\n", bound);
465 
466     hr = SafeArrayGetUBound(V_ARRAY(&value), 1, &bound);
467     ok(hr == S_OK, "got 0x%08x\n", hr);
468     ok(bound == 1, "got %u\n", bound);
469 
470     hr = SafeArrayGetVartype(V_ARRAY(&value), &vartype);
471     ok(hr == S_OK, "got 0x%08x\n", hr);
472     ok(vartype == VT_VARIANT, "got %d\n", vartype);
473 
474     bound = 0;
475     hr = SafeArrayGetElement(V_ARRAY(&value), &bound, &v);
476     ok(hr == S_OK, "got 0x%08x\n", hr);
477     ok(V_VT(&v) == VT_BSTR, "got %d\n", V_VT(&v));
478     ok(!lstrcmpW(V_BSTR(&v), fooW), "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
479     VariantClear(&v);
480     VariantClear(&value);
481 
482     name = SysAllocString(regsz1W);
483     V_VT(&value) = VT_I2;
484     hr = IWshShell3_RegRead(sh3, name, &value);
485     ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got 0x%08x\n", hr);
486     ok(V_VT(&value) == VT_I2, "got %d\n", V_VT(&value));
487     VariantClear(&value);
488     SysFreeString(name);
489 
490     delete_key(root);
491 
492     /* RegWrite() */
493     ret = RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &root);
494     ok(ret == 0, "got %d\n", ret);
495 
496     hr = IWshShell3_RegWrite(sh3, NULL, NULL, NULL);
497     ok(hr == E_POINTER, "got 0x%08x\n", hr);
498 
499     lstrcpyW(pathW, keypathW);
500     lstrcatW(pathW, regszW);
501     name = SysAllocString(pathW);
502 
503     hr = IWshShell3_RegWrite(sh3, name, NULL, NULL);
504     ok(hr == E_POINTER, "got 0x%08x\n", hr);
505 
506     VariantInit(&value);
507     hr = IWshShell3_RegWrite(sh3, name, &value, NULL);
508     ok(hr == E_POINTER, "got 0x%08x\n", hr);
509 
510     hr = IWshShell3_RegWrite(sh3, name, &value, &value);
511     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
512 
513     /* type is optional */
514     V_VT(&v) = VT_ERROR;
515     V_ERROR(&v) = DISP_E_PARAMNOTFOUND;
516     hr = IWshShell3_RegWrite(sh3, name, &value, &v);
517     ok(hr == S_OK, "got 0x%08x\n", hr);
518 
519     /* default type is REG_SZ */
520     V_VT(&value) = VT_I4;
521     V_I4(&value) = 12;
522     hr = IWshShell3_RegWrite(sh3, name, &value, &v);
523     ok(hr == S_OK, "got 0x%08x\n", hr);
524 
525     type = REG_NONE;
526     ret = RegQueryValueExA(root, "regsz", 0, &type, NULL, NULL);
527     ok(ret == ERROR_SUCCESS, "got %d\n", ret);
528     ok(type == REG_SZ, "got %d\n", type);
529 
530     ret = RegDeleteValueA(root, "regsz");
531     ok(ret == ERROR_SUCCESS, "got %d\n", ret);
532     V_VT(&value) = VT_BSTR;
533     V_BSTR(&value) = SysAllocString(regszW);
534     hr = IWshShell3_RegWrite(sh3, name, &value, &v);
535     ok(hr == S_OK, "got 0x%08x\n", hr);
536     VariantClear(&value);
537 
538     type = REG_NONE;
539     ret = RegQueryValueExA(root, "regsz", 0, &type, NULL, NULL);
540     ok(ret == ERROR_SUCCESS, "got %d\n", ret);
541     ok(type == REG_SZ, "got %d\n", type);
542 
543     ret = RegDeleteValueA(root, "regsz");
544     ok(ret == ERROR_SUCCESS, "got %d\n", ret);
545     V_VT(&value) = VT_R4;
546     V_R4(&value) = 1.2;
547     hr = IWshShell3_RegWrite(sh3, name, &value, &v);
548     ok(hr == S_OK, "got 0x%08x\n", hr);
549     VariantClear(&value);
550 
551     type = REG_NONE;
552     ret = RegQueryValueExA(root, "regsz", 0, &type, NULL, NULL);
553     ok(ret == ERROR_SUCCESS, "got %d\n", ret);
554     ok(type == REG_SZ, "got %d\n", type);
555 
556     ret = RegDeleteValueA(root, "regsz");
557     ok(ret == ERROR_SUCCESS, "got %d\n", ret);
558     V_VT(&value) = VT_R4;
559     V_R4(&value) = 1.2;
560     V_VT(&v) = VT_I2;
561     V_I2(&v) = 1;
562     hr = IWshShell3_RegWrite(sh3, name, &value, &v);
563     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
564     VariantClear(&value);
565 
566     SysFreeString(name);
567 
568     delete_key(root);
569     IWshShell3_Release(sh3);
570 }
571 
572 static void test_popup(void)
573 {
574     static const WCHAR textW[] = {'T','e','x','t',0};
575     VARIANT timeout, type, title, optional;
576     IWshShell *sh;
577     int button;
578     HRESULT hr;
579     BSTR text;
580 
581     hr = CoCreateInstance(&CLSID_WshShell, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER,
582             &IID_IWshShell, (void **)&sh);
583     ok(hr == S_OK, "Failed to create WshShell object, hr %#x.\n", hr);
584 
585     button = 123;
586     text = SysAllocString(textW);
587 
588     hr = IWshShell_Popup(sh, NULL, NULL, NULL, NULL, &button);
589     ok(hr == E_POINTER, "Unexpected retval %#x.\n", hr);
590     ok(button == 123, "Unexpected button id %d.\n", button);
591 
592     hr = IWshShell_Popup(sh, text, NULL, NULL, NULL, &button);
593     ok(hr == E_POINTER, "Unexpected retval %#x.\n", hr);
594     ok(button == 123, "Unexpected button id %d.\n", button);
595 
596     V_VT(&optional) = VT_ERROR;
597     V_ERROR(&optional) = DISP_E_PARAMNOTFOUND;
598 
599     V_VT(&timeout) = VT_I2;
600     V_I2(&timeout) = 1;
601 
602     V_VT(&type) = VT_I2;
603     V_I2(&type) = 1;
604 
605     V_VT(&title) = VT_BSTR;
606     V_BSTR(&title) = NULL;
607 
608     hr = IWshShell_Popup(sh, text, &timeout, &optional, &type, &button);
609     ok(hr == S_OK, "Unexpected retval %#x.\n", hr);
610     ok(button == -1, "Unexpected button id %d.\n", button);
611 
612     hr = IWshShell_Popup(sh, text, &timeout, &title, &optional, &button);
613     ok(hr == S_OK, "Unexpected retval %#x.\n", hr);
614     ok(button == -1, "Unexpected button id %d.\n", button);
615 
616     SysFreeString(text);
617     IWshShell_Release(sh);
618 }
619 
620 START_TEST(wshom)
621 {
622     IUnknown *unk;
623     HRESULT hr;
624 
625     CoInitialize(NULL);
626 
627     hr = CoCreateInstance(&CLSID_WshShell, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
628             &IID_IUnknown, (void**)&unk);
629     if (FAILED(hr)) {
630         win_skip("Could not create WshShell object: %08x\n", hr);
631         return;
632     }
633     IUnknown_Release(unk);
634 
635     test_wshshell();
636     test_registry();
637     test_popup();
638 
639     CoUninitialize();
640 }
641