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