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 
create_inf_file(LPCSTR filename,const char * data)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;
cbt_hook_proc(int nCode,WPARAM wParam,LPARAM lParam)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 
run_cmdline(LPCSTR section,int mode,LPCSTR path)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 
ok_registry(BOOL expectsuccess)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 */
test_cmdline(void)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 
test_registry(void)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 
test_install_from(void)177 static void test_install_from(void)
178 {
179     char path[MAX_PATH];
180     HINF infhandle;
181     HKEY key;
182     LONG res;
183     BOOL ret;
184 
185     /* First create a registry structure we would like to be deleted */
186     ok(!RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest\\setupapitest", &key),
187         "Expected RegCreateKeyA to succeed\n");
188 
189     /* Doublecheck if the registry key is present */
190     ok(!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest\\setupapitest", &key),
191         "Expected registry key to exist\n");
192 
193     create_inf_file(inffile, cmdline_inf_reg);
194     sprintf(path, "%s\\%s", CURR_DIR, inffile);
195     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
196     SetLastError(0xdeadbeef);
197     ret = SetupInstallFromInfSectionA(NULL, infhandle, "DefaultInstall", SPINST_REGISTRY, key,
198         "A:\\", 0, NULL, NULL, NULL, NULL);
199     ok(ret, "Unexpected failure\n");
200     ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
201 
202     /* Check if the registry key is recursively deleted */
203     res = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest", &key);
204     ok(res == ERROR_FILE_NOT_FOUND, "Didn't expect the registry key to exist\n");
205     /* Just in case */
206     if (res == ERROR_SUCCESS)
207     {
208         RegDeleteKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest\\setupapitest");
209         RegDeleteKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest");
210     }
211 
212     SetupCloseInfFile(infhandle);
213     DeleteFileA(inffile);
214 }
215 
test_install_svc_from(void)216 static void test_install_svc_from(void)
217 {
218     char inf[2048];
219     char path[MAX_PATH];
220     HINF infhandle;
221     BOOL ret;
222     SC_HANDLE scm_handle, svc_handle;
223 
224     /* Basic inf file to satisfy SetupOpenInfFileA */
225     strcpy(inf, "[Version]\nSignature=\"$Chicago$\"\n");
226     create_inf_file(inffile, inf);
227     sprintf(path, "%s\\%s", CURR_DIR, inffile);
228     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
229 
230     /* Nothing but the Version section */
231     SetLastError(0xdeadbeef);
232     ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
233     ok(!ret, "Expected failure\n");
234     ok(GetLastError() == ERROR_SECTION_NOT_FOUND,
235         "Expected ERROR_SECTION_NOT_FOUND, got %08x\n", GetLastError());
236     SetupCloseInfFile(infhandle);
237     DeleteFileA(inffile);
238 
239     /* Add the section */
240     strcat(inf, "[Winetest.Services]\n");
241     create_inf_file(inffile, inf);
242     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
243     SetLastError(0xdeadbeef);
244     ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
245     ok(!ret, "Expected failure\n");
246     ok(GetLastError() == ERROR_SECTION_NOT_FOUND,
247         "Expected ERROR_SECTION_NOT_FOUND, got %08x\n", GetLastError());
248     SetupCloseInfFile(infhandle);
249     DeleteFileA(inffile);
250 
251     /* Add a reference */
252     strcat(inf, "AddService=Winetest,,Winetest.Service\n");
253     create_inf_file(inffile, inf);
254     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
255     SetLastError(0xdeadbeef);
256     ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
257     ok(!ret, "Expected failure\n");
258     ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
259         "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError());
260     SetupCloseInfFile(infhandle);
261     DeleteFileA(inffile);
262 
263     /* Add the section */
264     strcat(inf, "[Winetest.Service]\n");
265     create_inf_file(inffile, inf);
266     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
267     SetLastError(0xdeadbeef);
268     ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
269     ok(!ret, "Expected failure\n");
270     ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
271         "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError());
272     SetupCloseInfFile(infhandle);
273     DeleteFileA(inffile);
274 
275     /* Just the ServiceBinary */
276     strcat(inf, "ServiceBinary=%12%\\winetest.sys\n");
277     create_inf_file(inffile, inf);
278     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
279     SetLastError(0xdeadbeef);
280     ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
281     ok(!ret, "Expected failure\n");
282     ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
283         "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError());
284     SetupCloseInfFile(infhandle);
285     DeleteFileA(inffile);
286 
287     /* Add the ServiceType */
288     strcat(inf, "ServiceType=1\n");
289     create_inf_file(inffile, inf);
290     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
291     SetLastError(0xdeadbeef);
292     ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
293     ok(!ret, "Expected failure\n");
294     ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
295         "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError());
296     SetupCloseInfFile(infhandle);
297     DeleteFileA(inffile);
298 
299     /* Add the StartType */
300     strcat(inf, "StartType=4\n");
301     create_inf_file(inffile, inf);
302     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
303     SetLastError(0xdeadbeef);
304     ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
305     ok(!ret, "Expected failure\n");
306     ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
307         "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError());
308     SetupCloseInfFile(infhandle);
309     DeleteFileA(inffile);
310 
311     /* This should be it, the minimal entries to install a service */
312     strcat(inf, "ErrorControl=1");
313     create_inf_file(inffile, inf);
314     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
315     SetLastError(0xdeadbeef);
316     ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
317     if (!ret && GetLastError() == ERROR_ACCESS_DENIED)
318     {
319         skip("Not enough rights to install the service\n");
320         SetupCloseInfFile(infhandle);
321         DeleteFileA(inffile);
322         return;
323     }
324     ok(ret, "Expected success\n");
325     ok(GetLastError() == ERROR_SUCCESS,
326         "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
327     SetupCloseInfFile(infhandle);
328     DeleteFileA(inffile);
329 
330     scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
331 
332     /* Open the service to see if it's really there */
333     svc_handle = OpenServiceA(scm_handle, "Winetest", DELETE);
334     ok(svc_handle != NULL, "Service was not created\n");
335 
336     SetLastError(0xdeadbeef);
337     ret = DeleteService(svc_handle);
338     ok(ret, "Service could not be deleted : %d\n", GetLastError());
339 
340     CloseServiceHandle(svc_handle);
341     CloseServiceHandle(scm_handle);
342 
343     strcpy(inf, "[Version]\nSignature=\"$Chicago$\"\n");
344     strcat(inf, "[XSP.InstallPerVer]\n");
345     strcat(inf, "AddReg=AspEventlogMsg.Reg,Perf.Reg,AspVersions.Reg,FreeADO.Reg,IndexServer.Reg\n");
346     create_inf_file(inffile, inf);
347     sprintf(path, "%s\\%s", CURR_DIR, inffile);
348     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
349 
350     SetLastError(0xdeadbeef);
351     ret = SetupInstallServicesFromInfSectionA(infhandle, "XSP.InstallPerVer", 0);
352     ok(ret, "Expected success\n");
353     ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
354     SetupCloseInfFile(infhandle);
355     DeleteFileA(inffile);
356 
357     /* TODO: Test the Flags */
358 }
359 
test_driver_install(void)360 static void test_driver_install(void)
361 {
362     HANDLE handle;
363     SC_HANDLE scm_handle, svc_handle;
364     BOOL ret;
365     char path[MAX_PATH], windir[MAX_PATH], driver[MAX_PATH];
366     DWORD attrs;
367     /* Minimal stuff needed */
368     static const char *inf =
369         "[Version]\n"
370         "Signature=\"$Chicago$\"\n"
371         "[DestinationDirs]\n"
372         "Winetest.DriverFiles=12\n"
373         "[DefaultInstall]\n"
374         "CopyFiles=Winetest.DriverFiles\n"
375         "[DefaultInstall.Services]\n"
376         "AddService=Winetest,,Winetest.Service\n"
377         "[Winetest.Service]\n"
378         "ServiceBinary=%12%\\winetest.sys\n"
379         "ServiceType=1\n"
380         "StartType=4\n"
381         "ErrorControl=1\n"
382         "[Winetest.DriverFiles]\n"
383         "winetest.sys";
384 
385     /* Bail out if we don't have enough rights */
386     SetLastError(0xdeadbeef);
387     scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
388     if (!scm_handle && (GetLastError() == ERROR_ACCESS_DENIED))
389     {
390         skip("Not enough rights to install the service\n");
391         return;
392     }
393     CloseServiceHandle(scm_handle);
394 
395     /* Place where we expect the driver to be installed */
396     GetWindowsDirectoryA(windir, MAX_PATH);
397     lstrcpyA(driver, windir);
398     lstrcatA(driver, "\\system32\\drivers\\winetest.sys");
399 
400     /* Create a dummy driver file */
401     handle = CreateFileA("winetest.sys", GENERIC_WRITE, 0, NULL,
402                            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
403     CloseHandle(handle);
404 
405     create_inf_file(inffile, inf);
406     sprintf(path, "%s\\%s", CURR_DIR, inffile);
407     run_cmdline("DefaultInstall", 128, path);
408 
409     /* Driver should have been installed */
410     attrs = GetFileAttributesA(driver);
411     ok(attrs != INVALID_FILE_ATTRIBUTES, "Expected driver to exist\n");
412 
413     scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
414 
415     /* Open the service to see if it's really there */
416     svc_handle = OpenServiceA(scm_handle, "Winetest", DELETE);
417     ok(svc_handle != NULL, "Service was not created\n");
418 
419     SetLastError(0xdeadbeef);
420     ret = DeleteService(svc_handle);
421     ok(ret, "Service could not be deleted : %d\n", GetLastError());
422 
423     CloseServiceHandle(svc_handle);
424     CloseServiceHandle(scm_handle);
425 
426     /* File cleanup */
427     DeleteFileA(inffile);
428     DeleteFileA("winetest.sys");
429     DeleteFileA(driver);
430 }
431 
test_profile_items(void)432 static void test_profile_items(void)
433 {
434     char path[MAX_PATH], commonprogs[MAX_PATH];
435 
436     static const char *inf =
437         "[Version]\n"
438         "Signature=\"$Chicago$\"\n"
439         "[DefaultInstall]\n"
440         "ProfileItems=TestItem,TestItem2,TestGroup\n"
441         "[TestItem]\n"
442         "Name=TestItem\n"
443         "CmdLine=11,,notepad.exe\n"
444         "[TestItem2]\n"
445         "Name=TestItem2\n"
446         "CmdLine=11,,notepad.exe\n"
447         "SubDir=TestDir\n"
448         "[TestGroup]\n"
449         "Name=TestGroup,4\n"
450         ;
451 
452     if (S_OK != SHGetFolderPathA(NULL, CSIDL_COMMON_PROGRAMS, NULL, SHGFP_TYPE_CURRENT, commonprogs))
453     {
454         skip("No common program files directory exists\n");
455         goto cleanup;
456     }
457 
458     snprintf(path, MAX_PATH, "%s\\TestDir", commonprogs);
459     if (!CreateDirectoryA(path, NULL) && GetLastError() == ERROR_ACCESS_DENIED)
460     {
461         skip("need admin rights\n");
462         return;
463     }
464     RemoveDirectoryA(path);
465 
466     create_inf_file(inffile, inf);
467     sprintf(path, "%s\\%s", CURR_DIR, inffile);
468     run_cmdline("DefaultInstall", 128, path);
469 
470     snprintf(path, MAX_PATH, "%s\\TestItem.lnk", commonprogs);
471     snprintf(path, MAX_PATH, "%s\\TestDir", commonprogs);
472     ok(INVALID_FILE_ATTRIBUTES != GetFileAttributesA(path), "directory not created\n");
473     snprintf(path, MAX_PATH, "%s\\TestDir\\TestItem2.lnk", commonprogs);
474     ok(INVALID_FILE_ATTRIBUTES != GetFileAttributesA(path), "link not created\n");
475     snprintf(path, MAX_PATH, "%s\\TestGroup", commonprogs);
476     ok(INVALID_FILE_ATTRIBUTES != GetFileAttributesA(path), "group not created\n");
477 
478     snprintf(path, MAX_PATH, "%s\\TestItem.lnk", commonprogs);
479     DeleteFileA(path);
480     snprintf(path, MAX_PATH, "%s\\TestDir\\TestItem2.lnk", commonprogs);
481     DeleteFileA(path);
482     snprintf(path, MAX_PATH, "%s\\TestItem2.lnk", commonprogs);
483     DeleteFileA(path);
484     snprintf(path, MAX_PATH, "%s\\TestDir", commonprogs);
485     RemoveDirectoryA(path);
486     snprintf(path, MAX_PATH, "%s\\TestGroup", commonprogs);
487     RemoveDirectoryA(path);
488 
489 cleanup:
490     DeleteFileA(inffile);
491 }
492 
test_inffilelistA(void)493 static void test_inffilelistA(void)
494 {
495     static const char inffile2[] = "test2.inf";
496     static const char *inf =
497         "[Version]\n"
498         "Signature=\"$Chicago$\"";
499 
500     char buffer[MAX_PATH] = { 0 };
501     char dir[MAX_PATH], *p;
502     DWORD expected, outsize;
503     BOOL ret;
504 
505     /* create a private directory, the temp directory may contain some
506      * inf files left over from old installations
507      */
508     if (!GetTempFileNameA(CURR_DIR, "inftest", 1, dir))
509     {
510         win_skip("GetTempFileNameA failed with error %d\n", GetLastError());
511         return;
512     }
513     if (!CreateDirectoryA(dir, NULL ))
514     {
515         win_skip("CreateDirectoryA(%s) failed with error %d\n", dir, GetLastError());
516         return;
517     }
518     if (!SetCurrentDirectoryA(dir))
519     {
520         win_skip("SetCurrentDirectoryA failed with error %d\n", GetLastError());
521         RemoveDirectoryA(dir);
522         return;
523     }
524 
525     create_inf_file(inffile, inf);
526     create_inf_file(inffile2, inf);
527 
528     /* mixed style
529      */
530     expected = 3 + strlen(inffile) + strlen(inffile2);
531     ret = SetupGetInfFileListA(dir, INF_STYLE_OLDNT | INF_STYLE_WIN4, buffer,
532                                MAX_PATH, &outsize);
533     ok(ret, "expected SetupGetInfFileListA to succeed!\n");
534     ok(expected == outsize, "expected required buffersize to be %d, got %d\n",
535          expected, outsize);
536     for(p = buffer; lstrlenA(p) && (outsize > (p - buffer)); p+=lstrlenA(p) + 1)
537         ok(!lstrcmpA(p,inffile2) || !lstrcmpA(p,inffile),
538             "unexpected filename %s\n",p);
539 
540     DeleteFileA(inffile);
541     DeleteFileA(inffile2);
542     SetCurrentDirectoryA(CURR_DIR);
543     RemoveDirectoryA(dir);
544 }
545 
test_inffilelist(void)546 static void test_inffilelist(void)
547 {
548     static const char inffile2[] = "test2.inf";
549     static const WCHAR inffile2W[] = {'t','e','s','t','2','.','i','n','f',0};
550     static const char invalid_inf[] = "invalid.inf";
551     static const WCHAR invalid_infW[] = {'i','n','v','a','l','i','d','.','i','n','f',0};
552     static const char *inf =
553         "[Version]\n"
554         "Signature=\"$Chicago$\"";
555     static const char *inf2 =
556         "[Version]\n"
557         "Signature=\"$CHICAGO$\"";
558     static const char *infNT =
559         "[Version]\n"
560         "Signature=\"$WINDOWS NT$\"";
561 
562     WCHAR *p, *ptr;
563     char dirA[MAX_PATH];
564     WCHAR dir[MAX_PATH] = { 0 };
565     WCHAR buffer[MAX_PATH] = { 0 };
566     DWORD expected, outsize;
567     BOOL ret;
568 
569     /* NULL means %windir%\\inf
570      * get the value as reference
571      */
572     expected = 0;
573     SetLastError(0xdeadbeef);
574     ret = SetupGetInfFileListW(NULL, INF_STYLE_WIN4, NULL, 0, &expected);
575     ok(ret, "expected SetupGetInfFileListW to succeed! Error: %d\n", GetLastError());
576     ok(expected > 0, "expected required buffersize to be at least 1\n");
577 
578     /* check if an empty string doesn't behaves like NULL */
579     outsize = 0;
580     SetLastError(0xdeadbeef);
581     ret = SetupGetInfFileListW(dir, INF_STYLE_WIN4, NULL, 0, &outsize);
582     ok(!ret, "expected SetupGetInfFileListW to fail!\n");
583 
584     /* create a private directory, the temp directory may contain some
585      * inf files left over from old installations
586      */
587     if (!GetTempFileNameA(CURR_DIR, "inftest", 1, dirA))
588     {
589         win_skip("GetTempFileNameA failed with error %d\n", GetLastError());
590         return;
591     }
592     if (!CreateDirectoryA(dirA, NULL ))
593     {
594         win_skip("CreateDirectoryA(%s) failed with error %d\n", dirA, GetLastError());
595         return;
596     }
597     if (!SetCurrentDirectoryA(dirA))
598     {
599         win_skip("SetCurrentDirectoryA failed with error %d\n", GetLastError());
600         RemoveDirectoryA(dirA);
601         return;
602     }
603 
604     MultiByteToWideChar(CP_ACP, 0, dirA, -1, dir, MAX_PATH);
605     /* check a not existing directory
606      */
607     ptr = dir + lstrlenW(dir);
608     MultiByteToWideChar(CP_ACP, 0, "\\not_existent", -1, ptr, MAX_PATH - lstrlenW(dir));
609     outsize = 0xffffffff;
610     SetLastError(0xdeadbeef);
611     ret = SetupGetInfFileListW(dir, INF_STYLE_WIN4, NULL, 0, &outsize);
612     ok(ret, "expected SetupGetInfFileListW to succeed!\n");
613     ok(outsize == 1, "expected required buffersize to be 1, got %d\n", outsize);
614     ok(ERROR_PATH_NOT_FOUND == GetLastError(),
615        "expected error ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
616 
617     create_inf_file(inffile, inf);
618     create_inf_file(inffile2, inf);
619     create_inf_file(invalid_inf, "This content does not match the inf file format");
620 
621     /* pass a filename instead of a directory
622      */
623     *ptr = '\\';
624     MultiByteToWideChar(CP_ACP, 0, invalid_inf, -1, ptr+1, MAX_PATH - lstrlenW(dir));
625     outsize = 0xffffffff;
626     SetLastError(0xdeadbeef);
627     ret = SetupGetInfFileListW(dir, INF_STYLE_WIN4, NULL, 0, &outsize);
628     ok(!ret, "expected SetupGetInfFileListW to fail!\n");
629     ok(ERROR_DIRECTORY == GetLastError(),
630        "expected error ERROR_DIRECTORY, got %d\n", GetLastError());
631 
632     /* make the filename look like directory
633      */
634     dir[1 + lstrlenW(dir)] = 0;
635     dir[lstrlenW(dir)] = '\\';
636     SetLastError(0xdeadbeef);
637     ret = SetupGetInfFileListW(dir, INF_STYLE_WIN4, NULL, 0, &outsize);
638     ok(!ret, "expected SetupGetInfFileListW to fail!\n");
639     ok(ERROR_DIRECTORY == GetLastError(),
640        "expected error ERROR_DIRECTORY, got %d\n", GetLastError());
641 
642     /* now check the buffer contents of a valid call
643      */
644     *ptr = 0;
645     expected = 3 + strlen(inffile) + strlen(inffile2);
646     ret = SetupGetInfFileListW(dir, INF_STYLE_WIN4, buffer, MAX_PATH, &outsize);
647     ok(ret, "expected SetupGetInfFileListW to succeed!\n");
648     ok(expected == outsize, "expected required buffersize to be %d, got %d\n",
649          expected, outsize);
650     for(p = buffer; lstrlenW(p) && (outsize > (p - buffer)); p+=lstrlenW(p) + 1)
651         ok(!lstrcmpW(p,inffile2W) || !lstrcmpW(p,inffileW),
652             "unexpected filename %s\n",wine_dbgstr_w(p));
653 
654     /* upper case value
655      */
656     create_inf_file(inffile2, inf2);
657     ret = SetupGetInfFileListW(dir, INF_STYLE_WIN4, buffer, MAX_PATH, &outsize);
658     ok(ret, "expected SetupGetInfFileListW to succeed!\n");
659     ok(expected == outsize, "expected required buffersize to be %d, got %d\n",
660          expected, outsize);
661     for(p = buffer; lstrlenW(p) && (outsize > (p - buffer)); p+=lstrlenW(p) + 1)
662         ok(!lstrcmpW(p,inffile2W) || !lstrcmpW(p,inffileW),
663             "unexpected filename %s\n",wine_dbgstr_w(p));
664 
665     /* signature Windows NT is also inf style win4
666      */
667     create_inf_file(inffile2, infNT);
668     expected = 3 + strlen(inffile) + strlen(inffile2);
669     ret = SetupGetInfFileListW(dir, INF_STYLE_WIN4, buffer, MAX_PATH, &outsize);
670     ok(ret, "expected SetupGetInfFileListW to succeed!\n");
671     ok(expected == outsize, "expected required buffersize to be %d, got %d\n",
672          expected, outsize);
673     for(p = buffer; lstrlenW(p) && (outsize > (p - buffer)); p+=lstrlenW(p) + 1)
674         ok(!lstrcmpW(p,inffile2W) || !lstrcmpW(p,inffileW),
675             "unexpected filename %s\n",wine_dbgstr_w(p));
676 
677     /* old style
678      */
679     expected = 2 + strlen(invalid_inf);
680     ret = SetupGetInfFileListW(dir, INF_STYLE_OLDNT, buffer, MAX_PATH, &outsize);
681     ok(ret, "expected SetupGetInfFileListW to succeed!\n");
682     ok(expected == outsize, "expected required buffersize to be %d, got %d\n",
683          expected, outsize);
684     for(p = buffer; lstrlenW(p) && (outsize > (p - buffer)); p+=lstrlenW(p) + 1)
685         ok(!lstrcmpW(p,invalid_infW), "unexpected filename %s\n",wine_dbgstr_w(p));
686 
687     /* mixed style
688      */
689     expected = 4 + strlen(inffile) + strlen(inffile2) + strlen(invalid_inf);
690     ret = SetupGetInfFileListW(dir, INF_STYLE_OLDNT | INF_STYLE_WIN4, buffer,
691                                MAX_PATH, &outsize);
692     ok(ret, "expected SetupGetInfFileListW to succeed!\n");
693     ok(expected == outsize, "expected required buffersize to be %d, got %d\n",
694          expected, outsize);
695     for(p = buffer; lstrlenW(p) && (outsize > (p - buffer)); p+=lstrlenW(p) + 1)
696         ok(!lstrcmpW(p,inffile2W) || !lstrcmpW(p,inffileW) || !lstrcmpW(p,invalid_infW),
697             "unexpected filename %s\n",wine_dbgstr_w(p));
698 
699     DeleteFileA(inffile);
700     DeleteFileA(inffile2);
701     DeleteFileA(invalid_inf);
702     SetCurrentDirectoryA(CURR_DIR);
703     RemoveDirectoryA(dirA);
704 }
705 
706 static const char dirid_inf[] = "[Version]\n"
707     "Signature=\"$Chicago$\"\n"
708     "[DefaultInstall]\n"
709     "AddReg=Add.Settings\n"
710     "[Add.Settings]\n"
711     "HKCU,Software\\Wine\\setupapitest,dirid,,%%%i%%\n";
712 
check_dirid(int dirid,LPCSTR expected)713 static void check_dirid(int dirid, LPCSTR expected)
714 {
715     char buffer[sizeof(dirid_inf)+11];
716     char path[MAX_PATH], actual[MAX_PATH];
717     LONG ret;
718     DWORD size, type;
719     HKEY key;
720 
721     sprintf(buffer, dirid_inf, dirid);
722 
723     create_inf_file(inffile, buffer);
724 
725     sprintf(path, "%s\\%s", CURR_DIR, inffile);
726     run_cmdline("DefaultInstall", 128, path);
727 
728     size = sizeof(actual);
729     actual[0] = '\0';
730     ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest", &key);
731     if (ret == ERROR_SUCCESS)
732     {
733         ret = RegQueryValueExA(key, "dirid", NULL, &type, (BYTE*)&actual, &size);
734         RegCloseKey(key);
735         if (type != REG_SZ)
736             ret = ERROR_FILE_NOT_FOUND;
737     }
738 
739     ok(ret == ERROR_SUCCESS, "Failed getting value for dirid %i, err=%d\n", dirid, ret);
740     ok(!strcmp(actual, expected), "Expected path for dirid %i was \"%s\", got \"%s\"\n", dirid, expected, actual);
741 
742     ok_registry(TRUE);
743     ret = DeleteFileA(inffile);
744     ok(ret, "Expected source inf to exist, last error was %d\n", GetLastError());
745 }
746 
747 /* Test dirid values */
test_dirid(void)748 static void test_dirid(void)
749 {
750     char expected[MAX_PATH];
751 
752     check_dirid(DIRID_NULL, "");
753 
754     GetWindowsDirectoryA(expected, MAX_PATH);
755     check_dirid(DIRID_WINDOWS, expected);
756 
757     GetSystemDirectoryA(expected, MAX_PATH);
758     check_dirid(DIRID_SYSTEM, expected);
759 
760     strcat(expected, "\\unknown");
761     check_dirid(40, expected);
762 }
763 
START_TEST(install)764 START_TEST(install)
765 {
766     char temp_path[MAX_PATH], prev_path[MAX_PATH];
767     DWORD len;
768 
769     GetCurrentDirectoryA(MAX_PATH, prev_path);
770     GetTempPathA(MAX_PATH, temp_path);
771     SetCurrentDirectoryA(temp_path);
772 
773     strcpy(CURR_DIR, temp_path);
774     len = strlen(CURR_DIR);
775     if(len && (CURR_DIR[len - 1] == '\\'))
776         CURR_DIR[len - 1] = 0;
777 
778     /* Set CBT hook to disallow MessageBox creation in current thread */
779     hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
780     assert(hhook != 0);
781 
782     test_cmdline();
783     test_registry();
784     test_install_from();
785     test_install_svc_from();
786     test_driver_install();
787     test_dirid();
788 
789     UnhookWindowsHookEx(hhook);
790 
791     /* We have to run this test after the CBT hook is disabled because
792         ProfileItems needs to create a window on Windows XP. */
793     test_profile_items();
794 
795     test_inffilelist();
796     test_inffilelistA();
797 
798     SetCurrentDirectoryA(prev_path);
799 }
800