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