1 /*
2  * Unit test for setupapi.dll install functions
3  *
4  * Copyright 2007 Misha Koshelev
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 <stdarg.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <assert.h>
25 
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "winuser.h"
30 #include "winreg.h"
31 #include "winsvc.h"
32 #include "setupapi.h"
33 #include "shlobj.h"
34 
35 #include "wine/test.h"
36 
37 static const char inffile[] = "test.inf";
38 static const WCHAR inffileW[] = {'t','e','s','t','.','i','n','f',0};
39 static char CURR_DIR[MAX_PATH];
40 
41 /* Notes on InstallHinfSectionA/W:
42  * - InstallHinfSectionA on WinXP seems to be a stub - it does not do anything
43  *   and simply returns without displaying any error message or setting last
44  *   error.
45  * - These functions do not return a value and do not always set last error to
46  *   ERROR_SUCCESS when installation still occurs (e.g., unquoted inf file with
47  *   spaces, registry keys are written but last error is 6).
48  * - On installation problems, a MessageBox() is displayed and a Beep() is
49  *   issued. The MessageBox() is disabled with a CBT hook.
50  */
51 
52 /*
53  * Helpers
54  */
55 
56 static void create_inf_file(LPCSTR filename, const char *data)
57 {
58     DWORD res;
59     BOOL ret;
60     HANDLE handle = CreateFileA(filename, GENERIC_WRITE, 0, NULL,
61                            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
62     assert(handle != INVALID_HANDLE_VALUE);
63     ret = WriteFile(handle, data, strlen(data), &res, NULL);
64     assert(ret != 0);
65     CloseHandle(handle);
66 }
67 
68 /* CBT hook to ensure a window (e.g., MessageBox) cannot be created */
69 static HHOOK hhook;
70 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
71 {
72     return nCode == HCBT_CREATEWND ? 1: CallNextHookEx(hhook, nCode, wParam, lParam);
73 }
74 
75 /*
76  * Tests
77  */
78 
79 static const char *cmdline_inf = "[Version]\n"
80     "Signature=\"$Chicago$\"\n"
81     "[DefaultInstall]\n"
82     "AddReg=Add.Settings\n"
83     "[Add.Settings]\n"
84     "HKCU,Software\\Wine\\setupapitest,,\n";
85 
86 static void run_cmdline(LPCSTR section, int mode, LPCSTR path)
87 {
88     CHAR cmdline[MAX_PATH * 2];
89     WCHAR cmdlinew[MAX_PATH * 2];
90 
91     sprintf(cmdline, "%s %d %s", section, mode, path);
92     MultiByteToWideChar(CP_ACP, 0, cmdline, -1, cmdlinew, MAX_PATH*2);
93     InstallHinfSectionW(NULL, NULL, cmdlinew, 0);
94 }
95 
96 static void ok_registry(BOOL expectsuccess)
97 {
98     LONG ret;
99 
100     /* Functional tests for success of install and clean up */
101     ret = RegDeleteKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest");
102     ok((expectsuccess && ret == ERROR_SUCCESS) ||
103        (!expectsuccess && ret == ERROR_FILE_NOT_FOUND),
104        "Expected registry key Software\\Wine\\setupapitest to %s, RegDeleteKey returned %d\n",
105        expectsuccess ? "exist" : "not exist",
106        ret);
107 }
108 
109 /* Test command line processing */
110 static void test_cmdline(void)
111 {
112     static const char infwithspaces[] = "test file.inf";
113     char path[MAX_PATH];
114     BOOL ret;
115 
116     create_inf_file(inffile, cmdline_inf);
117     sprintf(path, "%s\\%s", CURR_DIR, inffile);
118     run_cmdline("DefaultInstall", 128, path);
119     ok_registry(TRUE);
120     ret = DeleteFileA(inffile);
121     ok(ret, "Expected source inf to exist, last error was %d\n", GetLastError());
122 
123     /* Test handling of spaces in path, unquoted and quoted */
124     create_inf_file(infwithspaces, cmdline_inf);
125 
126     sprintf(path, "%s\\%s", CURR_DIR, infwithspaces);
127     run_cmdline("DefaultInstall", 128, path);
128     ok_registry(TRUE);
129 
130     sprintf(path, "\"%s\\%s\"", CURR_DIR, infwithspaces);
131     run_cmdline("DefaultInstall", 128, path);
132     ok_registry(FALSE);
133 
134     ret = DeleteFileA(infwithspaces);
135     ok(ret, "Expected source inf to exist, last error was %d\n", GetLastError());
136 }
137 
138 static const char *cmdline_inf_reg = "[Version]\n"
139     "Signature=\"$Chicago$\"\n"
140     "[DefaultInstall]\n"
141     "DelReg=Del.Settings\n"
142     "[Del.Settings]\n"
143     "HKCU,Software\\Wine\\setupapitest\n";
144 
145 static void test_registry(void)
146 {
147     HKEY key;
148     LONG res;
149     char path[MAX_PATH];
150     BOOL ret;
151 
152     /* First create a registry structure we would like to be deleted */
153     ok(!RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest\\setupapitest", &key),
154         "Expected RegCreateKeyA to succeed\n");
155 
156     /* Doublecheck if the registry key is present */
157     ok(!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest\\setupapitest", &key),
158         "Expected registry key to exist\n");
159 
160     create_inf_file(inffile, cmdline_inf_reg);
161     sprintf(path, "%s\\%s", CURR_DIR, inffile);
162     run_cmdline("DefaultInstall", 128, path);
163 
164     /* Check if the registry key is recursively deleted */
165     res = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest", &key);
166     ok(res == ERROR_FILE_NOT_FOUND, "Didn't expect the registry key to exist\n");
167     /* Just in case */
168     if (res == ERROR_SUCCESS)
169     {
170         RegDeleteKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest\\setupapitest");
171         RegDeleteKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest");
172     }
173     ret = DeleteFileA(inffile);
174     ok(ret, "Expected source inf to exist, last error was %d\n", GetLastError());
175 }
176 
177 static void test_install_svc_from(void)
178 {
179     char inf[2048];
180     char path[MAX_PATH];
181     HINF infhandle;
182     BOOL ret;
183     SC_HANDLE scm_handle, svc_handle;
184 
185     /* Basic inf file to satisfy SetupOpenInfFileA */
186     strcpy(inf, "[Version]\nSignature=\"$Chicago$\"\n");
187     create_inf_file(inffile, inf);
188     sprintf(path, "%s\\%s", CURR_DIR, inffile);
189     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
190 
191     /* Nothing but the Version section */
192     SetLastError(0xdeadbeef);
193     ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
194     ok(!ret, "Expected failure\n");
195     ok(GetLastError() == ERROR_SECTION_NOT_FOUND,
196         "Expected ERROR_SECTION_NOT_FOUND, got %08x\n", GetLastError());
197     SetupCloseInfFile(infhandle);
198     DeleteFileA(inffile);
199 
200     /* Add the section */
201     strcat(inf, "[Winetest.Services]\n");
202     create_inf_file(inffile, inf);
203     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
204     SetLastError(0xdeadbeef);
205     ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
206     ok(!ret, "Expected failure\n");
207     ok(GetLastError() == ERROR_SECTION_NOT_FOUND,
208         "Expected ERROR_SECTION_NOT_FOUND, got %08x\n", GetLastError());
209     SetupCloseInfFile(infhandle);
210     DeleteFileA(inffile);
211 
212     /* Add a reference */
213     strcat(inf, "AddService=Winetest,,Winetest.Service\n");
214     create_inf_file(inffile, inf);
215     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
216     SetLastError(0xdeadbeef);
217     ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
218     ok(!ret, "Expected failure\n");
219     ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
220         "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError());
221     SetupCloseInfFile(infhandle);
222     DeleteFileA(inffile);
223 
224     /* Add the section */
225     strcat(inf, "[Winetest.Service]\n");
226     create_inf_file(inffile, inf);
227     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
228     SetLastError(0xdeadbeef);
229     ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
230     ok(!ret, "Expected failure\n");
231     ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
232         "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError());
233     SetupCloseInfFile(infhandle);
234     DeleteFileA(inffile);
235 
236     /* Just the ServiceBinary */
237     strcat(inf, "ServiceBinary=%12%\\winetest.sys\n");
238     create_inf_file(inffile, inf);
239     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
240     SetLastError(0xdeadbeef);
241     ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
242     ok(!ret, "Expected failure\n");
243     ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
244         "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError());
245     SetupCloseInfFile(infhandle);
246     DeleteFileA(inffile);
247 
248     /* Add the ServiceType */
249     strcat(inf, "ServiceType=1\n");
250     create_inf_file(inffile, inf);
251     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
252     SetLastError(0xdeadbeef);
253     ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
254     ok(!ret, "Expected failure\n");
255     ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
256         "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError());
257     SetupCloseInfFile(infhandle);
258     DeleteFileA(inffile);
259 
260     /* Add the StartType */
261     strcat(inf, "StartType=4\n");
262     create_inf_file(inffile, inf);
263     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
264     SetLastError(0xdeadbeef);
265     ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
266     ok(!ret, "Expected failure\n");
267     ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
268         "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError());
269     SetupCloseInfFile(infhandle);
270     DeleteFileA(inffile);
271 
272     /* This should be it, the minimal entries to install a service */
273     strcat(inf, "ErrorControl=1");
274     create_inf_file(inffile, inf);
275     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
276     SetLastError(0xdeadbeef);
277     ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
278     if (!ret && GetLastError() == ERROR_ACCESS_DENIED)
279     {
280         skip("Not enough rights to install the service\n");
281         SetupCloseInfFile(infhandle);
282         DeleteFileA(inffile);
283         return;
284     }
285     ok(ret, "Expected success\n");
286     ok(GetLastError() == ERROR_SUCCESS,
287         "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
288     SetupCloseInfFile(infhandle);
289     DeleteFileA(inffile);
290 
291     scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
292 
293     /* Open the service to see if it's really there */
294     svc_handle = OpenServiceA(scm_handle, "Winetest", DELETE);
295     ok(svc_handle != NULL, "Service was not created\n");
296 
297     SetLastError(0xdeadbeef);
298     ret = DeleteService(svc_handle);
299     ok(ret, "Service could not be deleted : %d\n", GetLastError());
300 
301     CloseServiceHandle(svc_handle);
302     CloseServiceHandle(scm_handle);
303 
304     strcpy(inf, "[Version]\nSignature=\"$Chicago$\"\n");
305     strcat(inf, "[XSP.InstallPerVer]\n");
306     strcat(inf, "AddReg=AspEventlogMsg.Reg,Perf.Reg,AspVersions.Reg,FreeADO.Reg,IndexServer.Reg\n");
307     create_inf_file(inffile, inf);
308     sprintf(path, "%s\\%s", CURR_DIR, inffile);
309     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
310 
311     SetLastError(0xdeadbeef);
312     ret = SetupInstallServicesFromInfSectionA(infhandle, "XSP.InstallPerVer", 0);
313     ok(ret, "Expected success\n");
314     ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
315     SetupCloseInfFile(infhandle);
316     DeleteFileA(inffile);
317 
318     /* TODO: Test the Flags */
319 }
320 
321 static void test_driver_install(void)
322 {
323     HANDLE handle;
324     SC_HANDLE scm_handle, svc_handle;
325     BOOL ret;
326     char path[MAX_PATH], windir[MAX_PATH], driver[MAX_PATH];
327     DWORD attrs;
328     /* Minimal stuff needed */
329     static const char *inf =
330         "[Version]\n"
331         "Signature=\"$Chicago$\"\n"
332         "[DestinationDirs]\n"
333         "Winetest.DriverFiles=12\n"
334         "[DefaultInstall]\n"
335         "CopyFiles=Winetest.DriverFiles\n"
336         "[DefaultInstall.Services]\n"
337         "AddService=Winetest,,Winetest.Service\n"
338         "[Winetest.Service]\n"
339         "ServiceBinary=%12%\\winetest.sys\n"
340         "ServiceType=1\n"
341         "StartType=4\n"
342         "ErrorControl=1\n"
343         "[Winetest.DriverFiles]\n"
344         "winetest.sys";
345 
346     /* Bail out if we don't have enough rights */
347     SetLastError(0xdeadbeef);
348     scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
349     if (!scm_handle && (GetLastError() == ERROR_ACCESS_DENIED))
350     {
351         skip("Not enough rights to install the service\n");
352         return;
353     }
354     CloseServiceHandle(scm_handle);
355 
356     /* Place where we expect the driver to be installed */
357     GetWindowsDirectoryA(windir, MAX_PATH);
358     lstrcpyA(driver, windir);
359     lstrcatA(driver, "\\system32\\drivers\\winetest.sys");
360 
361     /* Create a dummy driver file */
362     handle = CreateFileA("winetest.sys", GENERIC_WRITE, 0, NULL,
363                            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
364     CloseHandle(handle);
365 
366     create_inf_file(inffile, inf);
367     sprintf(path, "%s\\%s", CURR_DIR, inffile);
368     run_cmdline("DefaultInstall", 128, path);
369 
370     /* Driver should have been installed */
371     attrs = GetFileAttributesA(driver);
372     ok(attrs != INVALID_FILE_ATTRIBUTES, "Expected driver to exist\n");
373 
374     scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
375 
376     /* Open the service to see if it's really there */
377     svc_handle = OpenServiceA(scm_handle, "Winetest", DELETE);
378     ok(svc_handle != NULL, "Service was not created\n");
379 
380     SetLastError(0xdeadbeef);
381     ret = DeleteService(svc_handle);
382     ok(ret, "Service could not be deleted : %d\n", GetLastError());
383 
384     CloseServiceHandle(svc_handle);
385     CloseServiceHandle(scm_handle);
386 
387     /* File cleanup */
388     DeleteFileA(inffile);
389     DeleteFileA("winetest.sys");
390     DeleteFileA(driver);
391 }
392 
393 static void test_profile_items(void)
394 {
395     char path[MAX_PATH], commonprogs[MAX_PATH];
396 
397     static const char *inf =
398         "[Version]\n"
399         "Signature=\"$Chicago$\"\n"
400         "[DefaultInstall]\n"
401         "ProfileItems=TestItem,TestItem2,TestGroup\n"
402         "[TestItem]\n"
403         "Name=TestItem\n"
404         "CmdLine=11,,notepad.exe\n"
405         "[TestItem2]\n"
406         "Name=TestItem2\n"
407         "CmdLine=11,,notepad.exe\n"
408         "SubDir=TestDir\n"
409         "[TestGroup]\n"
410         "Name=TestGroup,4\n"
411         ;
412 
413     if (S_OK != SHGetFolderPathA(NULL, CSIDL_COMMON_PROGRAMS, NULL, SHGFP_TYPE_CURRENT, commonprogs))
414     {
415         skip("No common program files directory exists\n");
416         goto cleanup;
417     }
418 
419     snprintf(path, MAX_PATH, "%s\\TestDir", commonprogs);
420     if (!CreateDirectoryA(path, NULL) && GetLastError() == ERROR_ACCESS_DENIED)
421     {
422         skip("need admin rights\n");
423         return;
424     }
425     RemoveDirectoryA(path);
426 
427     create_inf_file(inffile, inf);
428     sprintf(path, "%s\\%s", CURR_DIR, inffile);
429     run_cmdline("DefaultInstall", 128, path);
430 
431     snprintf(path, MAX_PATH, "%s\\TestItem.lnk", commonprogs);
432     snprintf(path, MAX_PATH, "%s\\TestDir", commonprogs);
433     ok(INVALID_FILE_ATTRIBUTES != GetFileAttributesA(path), "directory not created\n");
434     snprintf(path, MAX_PATH, "%s\\TestDir\\TestItem2.lnk", commonprogs);
435     ok(INVALID_FILE_ATTRIBUTES != GetFileAttributesA(path), "link not created\n");
436     snprintf(path, MAX_PATH, "%s\\TestGroup", commonprogs);
437     ok(INVALID_FILE_ATTRIBUTES != GetFileAttributesA(path), "group not created\n");
438 
439     snprintf(path, MAX_PATH, "%s\\TestItem.lnk", commonprogs);
440     DeleteFileA(path);
441     snprintf(path, MAX_PATH, "%s\\TestDir\\TestItem2.lnk", commonprogs);
442     DeleteFileA(path);
443     snprintf(path, MAX_PATH, "%s\\TestItem2.lnk", commonprogs);
444     DeleteFileA(path);
445     snprintf(path, MAX_PATH, "%s\\TestDir", commonprogs);
446     RemoveDirectoryA(path);
447     snprintf(path, MAX_PATH, "%s\\TestGroup", commonprogs);
448     RemoveDirectoryA(path);
449 
450 cleanup:
451     DeleteFileA(inffile);
452 }
453 
454 static void test_inffilelistA(void)
455 {
456     static const char inffile2[] = "test2.inf";
457     static const char *inf =
458         "[Version]\n"
459         "Signature=\"$Chicago$\"";
460 
461     char buffer[MAX_PATH] = { 0 };
462     char dir[MAX_PATH], *p;
463     DWORD expected, outsize;
464     BOOL ret;
465 
466     /* create a private directory, the temp directory may contain some
467      * inf files left over from old installations
468      */
469     if (!GetTempFileNameA(CURR_DIR, "inftest", 1, dir))
470     {
471         win_skip("GetTempFileNameA failed with error %d\n", GetLastError());
472         return;
473     }
474     if (!CreateDirectoryA(dir, NULL ))
475     {
476         win_skip("CreateDirectoryA(%s) failed with error %d\n", dir, GetLastError());
477         return;
478     }
479     if (!SetCurrentDirectoryA(dir))
480     {
481         win_skip("SetCurrentDirectoryA failed with error %d\n", GetLastError());
482         RemoveDirectoryA(dir);
483         return;
484     }
485 
486     create_inf_file(inffile, inf);
487     create_inf_file(inffile2, inf);
488 
489     /* mixed style
490      */
491     expected = 3 + strlen(inffile) + strlen(inffile2);
492     ret = SetupGetInfFileListA(dir, INF_STYLE_OLDNT | INF_STYLE_WIN4, buffer,
493                                MAX_PATH, &outsize);
494     ok(ret, "expected SetupGetInfFileListA to succeed!\n");
495     ok(expected == outsize, "expected required buffersize to be %d, got %d\n",
496          expected, outsize);
497     for(p = buffer; lstrlenA(p) && (outsize > (p - buffer)); p+=lstrlenA(p) + 1)
498         ok(!lstrcmpA(p,inffile2) || !lstrcmpA(p,inffile),
499             "unexpected filename %s\n",p);
500 
501     DeleteFileA(inffile);
502     DeleteFileA(inffile2);
503     SetCurrentDirectoryA(CURR_DIR);
504     RemoveDirectoryA(dir);
505 }
506 
507 static void test_inffilelist(void)
508 {
509     static const char inffile2[] = "test2.inf";
510     static const WCHAR inffile2W[] = {'t','e','s','t','2','.','i','n','f',0};
511     static const char invalid_inf[] = "invalid.inf";
512     static const WCHAR invalid_infW[] = {'i','n','v','a','l','i','d','.','i','n','f',0};
513     static const char *inf =
514         "[Version]\n"
515         "Signature=\"$Chicago$\"";
516     static const char *inf2 =
517         "[Version]\n"
518         "Signature=\"$CHICAGO$\"";
519     static const char *infNT =
520         "[Version]\n"
521         "Signature=\"$WINDOWS NT$\"";
522 
523     WCHAR *p, *ptr;
524     char dirA[MAX_PATH];
525     WCHAR dir[MAX_PATH] = { 0 };
526     WCHAR buffer[MAX_PATH] = { 0 };
527     DWORD expected, outsize;
528     BOOL ret;
529 
530     /* NULL means %windir%\\inf
531      * get the value as reference
532      */
533     expected = 0;
534     SetLastError(0xdeadbeef);
535     ret = SetupGetInfFileListW(NULL, INF_STYLE_WIN4, NULL, 0, &expected);
536     ok(ret, "expected SetupGetInfFileListW to succeed! Error: %d\n", GetLastError());
537     ok(expected > 0, "expected required buffersize to be at least 1\n");
538 
539     /* check if an empty string doesn't behaves like NULL */
540     outsize = 0;
541     SetLastError(0xdeadbeef);
542     ret = SetupGetInfFileListW(dir, INF_STYLE_WIN4, NULL, 0, &outsize);
543     ok(!ret, "expected SetupGetInfFileListW to fail!\n");
544 
545     /* create a private directory, the temp directory may contain some
546      * inf files left over from old installations
547      */
548     if (!GetTempFileNameA(CURR_DIR, "inftest", 1, dirA))
549     {
550         win_skip("GetTempFileNameA failed with error %d\n", GetLastError());
551         return;
552     }
553     if (!CreateDirectoryA(dirA, NULL ))
554     {
555         win_skip("CreateDirectoryA(%s) failed with error %d\n", dirA, GetLastError());
556         return;
557     }
558     if (!SetCurrentDirectoryA(dirA))
559     {
560         win_skip("SetCurrentDirectoryA failed with error %d\n", GetLastError());
561         RemoveDirectoryA(dirA);
562         return;
563     }
564 
565     MultiByteToWideChar(CP_ACP, 0, dirA, -1, dir, MAX_PATH);
566     /* check a not existing directory
567      */
568     ptr = dir + lstrlenW(dir);
569     MultiByteToWideChar(CP_ACP, 0, "\\not_existent", -1, ptr, MAX_PATH - lstrlenW(dir));
570     outsize = 0xffffffff;
571     SetLastError(0xdeadbeef);
572     ret = SetupGetInfFileListW(dir, INF_STYLE_WIN4, NULL, 0, &outsize);
573     ok(ret, "expected SetupGetInfFileListW to succeed!\n");
574     ok(outsize == 1, "expected required buffersize to be 1, got %d\n", outsize);
575     ok(ERROR_PATH_NOT_FOUND == GetLastError(),
576        "expected error ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
577 
578     create_inf_file(inffile, inf);
579     create_inf_file(inffile2, inf);
580     create_inf_file(invalid_inf, "This content does not match the inf file format");
581 
582     /* pass a filename instead of a directory
583      */
584     *ptr = '\\';
585     MultiByteToWideChar(CP_ACP, 0, invalid_inf, -1, ptr+1, MAX_PATH - lstrlenW(dir));
586     outsize = 0xffffffff;
587     SetLastError(0xdeadbeef);
588     ret = SetupGetInfFileListW(dir, INF_STYLE_WIN4, NULL, 0, &outsize);
589     ok(!ret, "expected SetupGetInfFileListW to fail!\n");
590     ok(ERROR_DIRECTORY == GetLastError(),
591        "expected error ERROR_DIRECTORY, got %d\n", GetLastError());
592 
593     /* make the filename look like directory
594      */
595     dir[1 + lstrlenW(dir)] = 0;
596     dir[lstrlenW(dir)] = '\\';
597     SetLastError(0xdeadbeef);
598     ret = SetupGetInfFileListW(dir, INF_STYLE_WIN4, NULL, 0, &outsize);
599     ok(!ret, "expected SetupGetInfFileListW to fail!\n");
600     ok(ERROR_DIRECTORY == GetLastError(),
601        "expected error ERROR_DIRECTORY, got %d\n", GetLastError());
602 
603     /* now check the buffer contents of a valid call
604      */
605     *ptr = 0;
606     expected = 3 + strlen(inffile) + strlen(inffile2);
607     ret = SetupGetInfFileListW(dir, INF_STYLE_WIN4, buffer, MAX_PATH, &outsize);
608     ok(ret, "expected SetupGetInfFileListW to succeed!\n");
609     ok(expected == outsize, "expected required buffersize to be %d, got %d\n",
610          expected, outsize);
611     for(p = buffer; lstrlenW(p) && (outsize > (p - buffer)); p+=lstrlenW(p) + 1)
612         ok(!lstrcmpW(p,inffile2W) || !lstrcmpW(p,inffileW),
613             "unexpected filename %s\n",wine_dbgstr_w(p));
614 
615     /* upper case value
616      */
617     create_inf_file(inffile2, inf2);
618     ret = SetupGetInfFileListW(dir, INF_STYLE_WIN4, buffer, MAX_PATH, &outsize);
619     ok(ret, "expected SetupGetInfFileListW to succeed!\n");
620     ok(expected == outsize, "expected required buffersize to be %d, got %d\n",
621          expected, outsize);
622     for(p = buffer; lstrlenW(p) && (outsize > (p - buffer)); p+=lstrlenW(p) + 1)
623         ok(!lstrcmpW(p,inffile2W) || !lstrcmpW(p,inffileW),
624             "unexpected filename %s\n",wine_dbgstr_w(p));
625 
626     /* signature Windows NT is also inf style win4
627      */
628     create_inf_file(inffile2, infNT);
629     expected = 3 + strlen(inffile) + strlen(inffile2);
630     ret = SetupGetInfFileListW(dir, INF_STYLE_WIN4, buffer, MAX_PATH, &outsize);
631     ok(ret, "expected SetupGetInfFileListW to succeed!\n");
632     ok(expected == outsize, "expected required buffersize to be %d, got %d\n",
633          expected, outsize);
634     for(p = buffer; lstrlenW(p) && (outsize > (p - buffer)); p+=lstrlenW(p) + 1)
635         ok(!lstrcmpW(p,inffile2W) || !lstrcmpW(p,inffileW),
636             "unexpected filename %s\n",wine_dbgstr_w(p));
637 
638     /* old style
639      */
640     expected = 2 + strlen(invalid_inf);
641     ret = SetupGetInfFileListW(dir, INF_STYLE_OLDNT, buffer, MAX_PATH, &outsize);
642     ok(ret, "expected SetupGetInfFileListW to succeed!\n");
643     ok(expected == outsize, "expected required buffersize to be %d, got %d\n",
644          expected, outsize);
645     for(p = buffer; lstrlenW(p) && (outsize > (p - buffer)); p+=lstrlenW(p) + 1)
646         ok(!lstrcmpW(p,invalid_infW), "unexpected filename %s\n",wine_dbgstr_w(p));
647 
648     /* mixed style
649      */
650     expected = 4 + strlen(inffile) + strlen(inffile2) + strlen(invalid_inf);
651     ret = SetupGetInfFileListW(dir, INF_STYLE_OLDNT | INF_STYLE_WIN4, buffer,
652                                MAX_PATH, &outsize);
653     ok(ret, "expected SetupGetInfFileListW to succeed!\n");
654     ok(expected == outsize, "expected required buffersize to be %d, got %d\n",
655          expected, outsize);
656     for(p = buffer; lstrlenW(p) && (outsize > (p - buffer)); p+=lstrlenW(p) + 1)
657         ok(!lstrcmpW(p,inffile2W) || !lstrcmpW(p,inffileW) || !lstrcmpW(p,invalid_infW),
658             "unexpected filename %s\n",wine_dbgstr_w(p));
659 
660     DeleteFileA(inffile);
661     DeleteFileA(inffile2);
662     DeleteFileA(invalid_inf);
663     SetCurrentDirectoryA(CURR_DIR);
664     RemoveDirectoryA(dirA);
665 }
666 
667 static const char dirid_inf[] = "[Version]\n"
668     "Signature=\"$Chicago$\"\n"
669     "[DefaultInstall]\n"
670     "AddReg=Add.Settings\n"
671     "[Add.Settings]\n"
672     "HKCU,Software\\Wine\\setupapitest,dirid,,%%%i%%\n";
673 
674 static void check_dirid(int dirid, LPCSTR expected)
675 {
676     char buffer[sizeof(dirid_inf)+11];
677     char path[MAX_PATH], actual[MAX_PATH];
678     LONG ret;
679     DWORD size, type;
680     HKEY key;
681 
682     sprintf(buffer, dirid_inf, dirid);
683 
684     create_inf_file(inffile, buffer);
685 
686     sprintf(path, "%s\\%s", CURR_DIR, inffile);
687     run_cmdline("DefaultInstall", 128, path);
688 
689     size = sizeof(actual);
690     actual[0] = '\0';
691     ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest", &key);
692     if (ret == ERROR_SUCCESS)
693     {
694         ret = RegQueryValueExA(key, "dirid", NULL, &type, (BYTE*)&actual, &size);
695         RegCloseKey(key);
696         if (type != REG_SZ)
697             ret = ERROR_FILE_NOT_FOUND;
698     }
699 
700     ok(ret == ERROR_SUCCESS, "Failed getting value for dirid %i, err=%d\n", dirid, ret);
701     ok(!strcmp(actual, expected), "Expected path for dirid %i was \"%s\", got \"%s\"\n", dirid, expected, actual);
702 
703     ok_registry(TRUE);
704     ret = DeleteFileA(inffile);
705     ok(ret, "Expected source inf to exist, last error was %d\n", GetLastError());
706 }
707 
708 /* Test dirid values */
709 static void test_dirid(void)
710 {
711     char expected[MAX_PATH];
712 
713     check_dirid(DIRID_NULL, "");
714 
715     GetWindowsDirectoryA(expected, MAX_PATH);
716     check_dirid(DIRID_WINDOWS, expected);
717 
718     GetSystemDirectoryA(expected, MAX_PATH);
719     check_dirid(DIRID_SYSTEM, expected);
720 
721     strcat(expected, "\\unknown");
722     check_dirid(40, expected);
723 }
724 
725 START_TEST(install)
726 {
727     char temp_path[MAX_PATH], prev_path[MAX_PATH];
728     DWORD len;
729 
730     GetCurrentDirectoryA(MAX_PATH, prev_path);
731     GetTempPathA(MAX_PATH, temp_path);
732     SetCurrentDirectoryA(temp_path);
733 
734     strcpy(CURR_DIR, temp_path);
735     len = strlen(CURR_DIR);
736     if(len && (CURR_DIR[len - 1] == '\\'))
737         CURR_DIR[len - 1] = 0;
738 
739     /* Set CBT hook to disallow MessageBox creation in current thread */
740     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
741     assert(hhook != 0);
742 
743     test_cmdline();
744     test_registry();
745     test_install_svc_from();
746     test_driver_install();
747     test_dirid();
748 
749     UnhookWindowsHookEx(hhook);
750 
751     /* We have to run this test after the CBT hook is disabled because
752         ProfileItems needs to create a window on Windows XP. */
753     test_profile_items();
754 
755     test_inffilelist();
756     test_inffilelistA();
757 
758     SetCurrentDirectoryA(prev_path);
759 }
760