po: Update Lithuanian translation.
[wine.git] / dlls / setupapi / tests / install.c
blob5015e3166d6cd5511098c0b0c4621a7b02e4ba83
1 /*
2 * Unit test for setupapi.dll install functions
4 * Copyright 2007 Misha Koshelev
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.
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.
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
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <assert.h>
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"
35 #include "wine/test.h"
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];
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.
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);
60 * Helpers
63 static void create_inf_file(LPCSTR filename, const char *data)
65 DWORD res;
66 BOOL ret;
67 HANDLE handle = CreateFileA(filename, GENERIC_WRITE, 0, NULL,
68 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
69 assert(handle != INVALID_HANDLE_VALUE);
70 ret = WriteFile(handle, data, strlen(data), &res, NULL);
71 assert(ret != 0);
72 CloseHandle(handle);
75 /* CBT hook to ensure a window (e.g., MessageBox) cannot be created */
76 static HHOOK hhook;
77 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
79 return nCode == HCBT_CREATEWND ? 1: CallNextHookEx(hhook, nCode, wParam, lParam);
83 * Tests
86 static const char *cmdline_inf = "[Version]\n"
87 "Signature=\"$Chicago$\"\n"
88 "[DefaultInstall]\n"
89 "AddReg=Add.Settings\n"
90 "[Add.Settings]\n"
91 "HKCU,Software\\Wine\\setupapitest,,\n";
93 static void run_cmdline(LPCSTR section, int mode, LPCSTR path)
95 CHAR cmdline[MAX_PATH * 2];
97 sprintf(cmdline, "%s %d %s", section, mode, path);
98 if (pInstallHinfSectionA) pInstallHinfSectionA(NULL, NULL, cmdline, 0);
99 else
101 WCHAR cmdlinew[MAX_PATH * 2];
102 MultiByteToWideChar(CP_ACP, 0, cmdline, -1, cmdlinew, MAX_PATH*2);
103 pInstallHinfSectionW(NULL, NULL, cmdlinew, 0);
107 static void ok_registry(BOOL expectsuccess)
109 LONG ret;
111 /* Functional tests for success of install and clean up */
112 ret = RegDeleteKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest");
113 ok((expectsuccess && ret == ERROR_SUCCESS) ||
114 (!expectsuccess && ret == ERROR_FILE_NOT_FOUND),
115 "Expected registry key Software\\Wine\\setupapitest to %s, RegDeleteKey returned %d\n",
116 expectsuccess ? "exist" : "not exist",
117 ret);
120 /* Test command line processing */
121 static void test_cmdline(void)
123 static const char infwithspaces[] = "test file.inf";
124 char path[MAX_PATH];
125 BOOL ret;
127 create_inf_file(inffile, cmdline_inf);
128 sprintf(path, "%s\\%s", CURR_DIR, inffile);
129 run_cmdline("DefaultInstall", 128, path);
130 ok_registry(TRUE);
131 ret = DeleteFileA(inffile);
132 ok(ret, "Expected source inf to exist, last error was %d\n", GetLastError());
134 /* Test handling of spaces in path, unquoted and quoted */
135 create_inf_file(infwithspaces, cmdline_inf);
137 sprintf(path, "%s\\%s", CURR_DIR, infwithspaces);
138 run_cmdline("DefaultInstall", 128, path);
139 ok_registry(TRUE);
141 sprintf(path, "\"%s\\%s\"", CURR_DIR, infwithspaces);
142 run_cmdline("DefaultInstall", 128, path);
143 ok_registry(FALSE);
145 ret = DeleteFileA(infwithspaces);
146 ok(ret, "Expected source inf to exist, last error was %d\n", GetLastError());
149 static const char *cmdline_inf_reg = "[Version]\n"
150 "Signature=\"$Chicago$\"\n"
151 "[DefaultInstall]\n"
152 "DelReg=Del.Settings\n"
153 "[Del.Settings]\n"
154 "HKCU,Software\\Wine\\setupapitest\n";
156 static void test_registry(void)
158 HKEY key;
159 LONG res;
160 char path[MAX_PATH];
161 BOOL ret;
163 /* First create a registry structure we would like to be deleted */
164 ok(!RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest\\setupapitest", &key),
165 "Expected RegCreateKeyA to succeed\n");
167 /* Doublecheck if the registry key is present */
168 ok(!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest\\setupapitest", &key),
169 "Expected registry key to exist\n");
171 create_inf_file(inffile, cmdline_inf_reg);
172 sprintf(path, "%s\\%s", CURR_DIR, inffile);
173 run_cmdline("DefaultInstall", 128, path);
175 /* Check if the registry key is recursively deleted */
176 res = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest", &key);
177 todo_wine
178 ok(res == ERROR_FILE_NOT_FOUND, "Didn't expect the registry key to exist\n");
179 /* Just in case */
180 if (res == ERROR_SUCCESS)
182 RegDeleteKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest\\setupapitest");
183 RegDeleteKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest");
185 ret = DeleteFileA(inffile);
186 ok(ret, "Expected source inf to exist, last error was %d\n", GetLastError());
189 static void test_install_svc_from(void)
191 char inf[2048];
192 char path[MAX_PATH];
193 HINF infhandle;
194 BOOL ret;
195 SC_HANDLE scm_handle, svc_handle;
197 /* Bail out if we are on win98 */
198 SetLastError(0xdeadbeef);
199 scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
201 if (!scm_handle && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED))
203 win_skip("OpenSCManagerA is not implemented, we are most likely on win9x\n");
204 return;
206 CloseServiceHandle(scm_handle);
208 /* Basic inf file to satisfy SetupOpenInfFileA */
209 strcpy(inf, "[Version]\nSignature=\"$Chicago$\"\n");
210 create_inf_file(inffile, inf);
211 sprintf(path, "%s\\%s", CURR_DIR, inffile);
212 infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
214 /* Nothing but the Version section */
215 SetLastError(0xdeadbeef);
216 ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
217 ok(!ret, "Expected failure\n");
218 ok(GetLastError() == ERROR_SECTION_NOT_FOUND,
219 "Expected ERROR_SECTION_NOT_FOUND, got %08x\n", GetLastError());
220 SetupCloseInfFile(infhandle);
221 DeleteFileA(inffile);
223 /* Add the section */
224 strcat(inf, "[Winetest.Services]\n");
225 create_inf_file(inffile, inf);
226 infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
227 SetLastError(0xdeadbeef);
228 ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
229 ok(!ret, "Expected failure\n");
230 ok(GetLastError() == ERROR_SECTION_NOT_FOUND,
231 "Expected ERROR_SECTION_NOT_FOUND, got %08x\n", GetLastError());
232 SetupCloseInfFile(infhandle);
233 DeleteFileA(inffile);
235 /* Add a reference */
236 strcat(inf, "AddService=Winetest,,Winetest.Service\n");
237 create_inf_file(inffile, inf);
238 infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
239 SetLastError(0xdeadbeef);
240 ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
241 ok(!ret, "Expected failure\n");
242 ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
243 "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError());
244 SetupCloseInfFile(infhandle);
245 DeleteFileA(inffile);
247 /* Add the section */
248 strcat(inf, "[Winetest.Service]\n");
249 create_inf_file(inffile, inf);
250 infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
251 SetLastError(0xdeadbeef);
252 ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
253 ok(!ret, "Expected failure\n");
254 ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
255 "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError());
256 SetupCloseInfFile(infhandle);
257 DeleteFileA(inffile);
259 /* Just the ServiceBinary */
260 strcat(inf, "ServiceBinary=%12%\\winetest.sys\n");
261 create_inf_file(inffile, inf);
262 infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
263 SetLastError(0xdeadbeef);
264 ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
265 ok(!ret, "Expected failure\n");
266 ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
267 "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError());
268 SetupCloseInfFile(infhandle);
269 DeleteFileA(inffile);
271 /* Add the ServiceType */
272 strcat(inf, "ServiceType=1\n");
273 create_inf_file(inffile, inf);
274 infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
275 SetLastError(0xdeadbeef);
276 ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
277 ok(!ret, "Expected failure\n");
278 ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
279 "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError());
280 SetupCloseInfFile(infhandle);
281 DeleteFileA(inffile);
283 /* Add the StartType */
284 strcat(inf, "StartType=4\n");
285 create_inf_file(inffile, inf);
286 infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
287 SetLastError(0xdeadbeef);
288 ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
289 ok(!ret, "Expected failure\n");
290 ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
291 "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", GetLastError());
292 SetupCloseInfFile(infhandle);
293 DeleteFileA(inffile);
295 /* This should be it, the minimal entries to install a service */
296 strcat(inf, "ErrorControl=1");
297 create_inf_file(inffile, inf);
298 infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
299 SetLastError(0xdeadbeef);
300 ret = SetupInstallServicesFromInfSectionA(infhandle, "Winetest.Services", 0);
301 if (!ret && GetLastError() == ERROR_ACCESS_DENIED)
303 skip("Not enough rights to install the service\n");
304 SetupCloseInfFile(infhandle);
305 DeleteFileA(inffile);
306 return;
308 ok(ret, "Expected success\n");
309 ok(GetLastError() == ERROR_SUCCESS,
310 "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
311 SetupCloseInfFile(infhandle);
312 DeleteFileA(inffile);
314 scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
316 /* Open the service to see if it's really there */
317 svc_handle = OpenServiceA(scm_handle, "Winetest", DELETE);
318 ok(svc_handle != NULL, "Service was not created\n");
320 SetLastError(0xdeadbeef);
321 ret = DeleteService(svc_handle);
322 ok(ret, "Service could not be deleted : %d\n", GetLastError());
324 CloseServiceHandle(svc_handle);
325 CloseServiceHandle(scm_handle);
327 strcpy(inf, "[Version]\nSignature=\"$Chicago$\"\n");
328 strcat(inf, "[XSP.InstallPerVer]\n");
329 strcat(inf, "AddReg=AspEventlogMsg.Reg,Perf.Reg,AspVersions.Reg,FreeADO.Reg,IndexServer.Reg\n");
330 create_inf_file(inffile, inf);
331 sprintf(path, "%s\\%s", CURR_DIR, inffile);
332 infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
334 SetLastError(0xdeadbeef);
335 ret = SetupInstallServicesFromInfSectionA(infhandle, "XSP.InstallPerVer", 0);
336 ok(ret, "Expected success\n");
337 ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %08x\n", GetLastError());
338 SetupCloseInfFile(infhandle);
339 DeleteFileA(inffile);
341 /* TODO: Test the Flags */
344 static void test_driver_install(void)
346 HANDLE handle;
347 SC_HANDLE scm_handle, svc_handle;
348 BOOL ret;
349 char path[MAX_PATH], windir[MAX_PATH], driver[MAX_PATH];
350 DWORD attrs;
351 /* Minimal stuff needed */
352 static const char *inf =
353 "[Version]\n"
354 "Signature=\"$Chicago$\"\n"
355 "[DestinationDirs]\n"
356 "Winetest.DriverFiles=12\n"
357 "[DefaultInstall]\n"
358 "CopyFiles=Winetest.DriverFiles\n"
359 "[DefaultInstall.Services]\n"
360 "AddService=Winetest,,Winetest.Service\n"
361 "[Winetest.Service]\n"
362 "ServiceBinary=%12%\\winetest.sys\n"
363 "ServiceType=1\n"
364 "StartType=4\n"
365 "ErrorControl=1\n"
366 "[Winetest.DriverFiles]\n"
367 "winetest.sys";
369 /* Bail out if we are on win98 */
370 SetLastError(0xdeadbeef);
371 scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
373 if (!scm_handle && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED))
375 win_skip("OpenSCManagerA is not implemented, we are most likely on win9x\n");
376 return;
378 else if (!scm_handle && (GetLastError() == ERROR_ACCESS_DENIED))
380 skip("Not enough rights to install the service\n");
381 return;
383 CloseServiceHandle(scm_handle);
385 /* Place where we expect the driver to be installed */
386 GetWindowsDirectoryA(windir, MAX_PATH);
387 lstrcpyA(driver, windir);
388 lstrcatA(driver, "\\system32\\drivers\\winetest.sys");
390 /* Create a dummy driver file */
391 handle = CreateFileA("winetest.sys", GENERIC_WRITE, 0, NULL,
392 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
393 CloseHandle(handle);
395 create_inf_file(inffile, inf);
396 sprintf(path, "%s\\%s", CURR_DIR, inffile);
397 run_cmdline("DefaultInstall", 128, path);
399 /* Driver should have been installed */
400 attrs = GetFileAttributesA(driver);
401 ok(attrs != INVALID_FILE_ATTRIBUTES, "Expected driver to exist\n");
403 scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
405 /* Open the service to see if it's really there */
406 svc_handle = OpenServiceA(scm_handle, "Winetest", DELETE);
407 ok(svc_handle != NULL, "Service was not created\n");
409 SetLastError(0xdeadbeef);
410 ret = DeleteService(svc_handle);
411 ok(ret, "Service could not be deleted : %d\n", GetLastError());
413 CloseServiceHandle(svc_handle);
414 CloseServiceHandle(scm_handle);
416 /* File cleanup */
417 DeleteFileA(inffile);
418 DeleteFileA("winetest.sys");
419 DeleteFileA(driver);
422 static void test_profile_items(void)
424 char path[MAX_PATH], commonprogs[MAX_PATH];
425 HMODULE hShell32;
426 BOOL (WINAPI *pSHGetFolderPathA)(HWND hwnd, int nFolder, HANDLE hToken, DWORD dwFlags, LPSTR pszPath);
428 static const char *inf =
429 "[Version]\n"
430 "Signature=\"$Chicago$\"\n"
431 "[DefaultInstall]\n"
432 "ProfileItems=TestItem,TestItem2,TestGroup\n"
433 "[TestItem]\n"
434 "Name=TestItem\n"
435 "CmdLine=11,,notepad.exe\n"
436 "[TestItem2]\n"
437 "Name=TestItem2\n"
438 "CmdLine=11,,notepad.exe\n"
439 "SubDir=TestDir\n"
440 "[TestGroup]\n"
441 "Name=TestGroup,4\n"
444 hShell32 = LoadLibraryA("shell32");
445 pSHGetFolderPathA = (void*)GetProcAddress(hShell32, "SHGetFolderPathA");
446 if (!pSHGetFolderPathA)
448 win_skip("SHGetFolderPathA is not available\n");
449 goto cleanup;
452 if (S_OK != pSHGetFolderPathA(NULL, CSIDL_COMMON_PROGRAMS, NULL, SHGFP_TYPE_CURRENT, commonprogs))
454 skip("No common program files directory exists\n");
455 goto cleanup;
458 create_inf_file(inffile, inf);
459 sprintf(path, "%s\\%s", CURR_DIR, inffile);
460 run_cmdline("DefaultInstall", 128, path);
462 snprintf(path, MAX_PATH, "%s\\TestItem.lnk", commonprogs);
463 if (INVALID_FILE_ATTRIBUTES == GetFileAttributesA(path))
465 win_skip("ProfileItems not implemented on this system\n");
467 else
469 snprintf(path, MAX_PATH, "%s\\TestDir", commonprogs);
470 ok(INVALID_FILE_ATTRIBUTES != GetFileAttributesA(path), "directory not created\n");
471 snprintf(path, MAX_PATH, "%s\\TestDir\\TestItem2.lnk", commonprogs);
472 ok(INVALID_FILE_ATTRIBUTES != GetFileAttributesA(path), "link not created\n");
473 snprintf(path, MAX_PATH, "%s\\TestGroup", commonprogs);
474 ok(INVALID_FILE_ATTRIBUTES != GetFileAttributesA(path), "group not created\n");
477 snprintf(path, MAX_PATH, "%s\\TestItem.lnk", commonprogs);
478 DeleteFileA(path);
479 snprintf(path, MAX_PATH, "%s\\TestDir\\TestItem2.lnk", commonprogs);
480 DeleteFileA(path);
481 snprintf(path, MAX_PATH, "%s\\TestItem2.lnk", commonprogs);
482 DeleteFileA(path);
483 snprintf(path, MAX_PATH, "%s\\TestDir", commonprogs);
484 RemoveDirectoryA(path);
485 snprintf(path, MAX_PATH, "%s\\TestGroup", commonprogs);
486 RemoveDirectoryA(path);
488 cleanup:
489 if (hShell32) FreeLibrary(hShell32);
490 DeleteFileA(inffile);
493 static void test_inffilelistA(void)
495 static const char inffile2[] = "test2.inf";
496 static const char *inf =
497 "[Version]\n"
498 "Signature=\"$Chicago$\"";
500 char buffer[MAX_PATH] = { 0 };
501 char dir[MAX_PATH], *p;
502 DWORD expected, outsize;
503 BOOL ret;
505 if(!pSetupGetInfFileListA)
507 win_skip("SetupGetInfFileListA not present\n");
508 return;
511 /* create a private directory, the temp directory may contain some
512 * inf files left over from old installations
514 if (!GetTempFileNameA(CURR_DIR, "inftest", 1, dir))
516 win_skip("GetTempFileNameA failed with error %d\n", GetLastError());
517 return;
519 if (!CreateDirectoryA(dir, NULL ))
521 win_skip("CreateDirectoryA(%s) failed with error %d\n", dir, GetLastError());
522 return;
524 if (!SetCurrentDirectoryA(dir))
526 win_skip("SetCurrentDirectoryA failed with error %d\n", GetLastError());
527 RemoveDirectoryA(dir);
528 return;
531 create_inf_file(inffile, inf);
532 create_inf_file(inffile2, inf);
534 /* mixed style
536 expected = 3 + strlen(inffile) + strlen(inffile2);
537 ret = pSetupGetInfFileListA(dir, INF_STYLE_OLDNT | INF_STYLE_WIN4, buffer,
538 MAX_PATH, &outsize);
539 ok(ret, "expected SetupGetInfFileListA to succeed!\n");
540 ok(expected == outsize, "expected required buffersize to be %d, got %d\n",
541 expected, outsize);
542 for(p = buffer; lstrlenA(p) && (outsize > (p - buffer)); p+=lstrlenA(p) + 1)
543 ok(!lstrcmpA(p,inffile2) || !lstrcmpA(p,inffile),
544 "unexpected filename %s\n",p);
546 DeleteFileA(inffile);
547 DeleteFileA(inffile2);
548 SetCurrentDirectoryA(CURR_DIR);
549 RemoveDirectoryA(dir);
552 static void test_inffilelist(void)
554 static const char inffile2[] = "test2.inf";
555 static const WCHAR inffile2W[] = {'t','e','s','t','2','.','i','n','f',0};
556 static const char invalid_inf[] = "invalid.inf";
557 static const WCHAR invalid_infW[] = {'i','n','v','a','l','i','d','.','i','n','f',0};
558 static const char *inf =
559 "[Version]\n"
560 "Signature=\"$Chicago$\"";
561 static const char *inf2 =
562 "[Version]\n"
563 "Signature=\"$CHICAGO$\"";
564 static const char *infNT =
565 "[Version]\n"
566 "Signature=\"$WINDOWS NT$\"";
568 WCHAR *p, *ptr;
569 char dirA[MAX_PATH];
570 WCHAR dir[MAX_PATH] = { 0 };
571 WCHAR buffer[MAX_PATH] = { 0 };
572 DWORD expected, outsize;
573 BOOL ret;
575 if(!pSetupGetInfFileListW)
577 win_skip("SetupGetInfFileListW not present\n");
578 return;
581 /* NULL means %windir%\\inf
582 * get the value as reference
584 expected = 0;
585 SetLastError(0xdeadbeef);
586 ret = pSetupGetInfFileListW(NULL, INF_STYLE_WIN4, NULL, 0, &expected);
587 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
589 win_skip("SetupGetInfFileListW not implemented\n");
590 return;
592 ok(ret, "expected SetupGetInfFileListW to succeed! Error: %d\n", GetLastError());
593 ok(expected > 0, "expected required buffersize to be at least 1\n");
595 /* check if an empty string doesn't behaves like NULL */
596 outsize = 0;
597 SetLastError(0xdeadbeef);
598 ret = pSetupGetInfFileListW(dir, INF_STYLE_WIN4, NULL, 0, &outsize);
599 ok(!ret, "expected SetupGetInfFileListW to fail!\n");
601 /* create a private directory, the temp directory may contain some
602 * inf files left over from old installations
604 if (!GetTempFileNameA(CURR_DIR, "inftest", 1, dirA))
606 win_skip("GetTempFileNameA failed with error %d\n", GetLastError());
607 return;
609 if (!CreateDirectoryA(dirA, NULL ))
611 win_skip("CreateDirectoryA(%s) failed with error %d\n", dirA, GetLastError());
612 return;
614 if (!SetCurrentDirectoryA(dirA))
616 win_skip("SetCurrentDirectoryA failed with error %d\n", GetLastError());
617 RemoveDirectoryA(dirA);
618 return;
621 MultiByteToWideChar(CP_ACP, 0, dirA, -1, dir, MAX_PATH);
622 /* check a not existing directory
624 ptr = dir + lstrlenW(dir);
625 MultiByteToWideChar(CP_ACP, 0, "\\not_existent", -1, ptr, MAX_PATH - lstrlenW(dir));
626 outsize = 0xffffffff;
627 SetLastError(0xdeadbeef);
628 ret = pSetupGetInfFileListW(dir, INF_STYLE_WIN4, NULL, 0, &outsize);
629 ok(ret, "expected SetupGetInfFileListW to succeed!\n");
630 ok(outsize == 1, "expected required buffersize to be 1, got %d\n", outsize);
631 ok(ERROR_PATH_NOT_FOUND == GetLastError(),
632 "expected error ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
634 create_inf_file(inffile, inf);
635 create_inf_file(inffile2, inf);
636 create_inf_file(invalid_inf, "This content does not match the inf file format");
638 /* pass a filename instead of a directory
640 *ptr = '\\';
641 MultiByteToWideChar(CP_ACP, 0, invalid_inf, -1, ptr+1, MAX_PATH - lstrlenW(dir));
642 outsize = 0xffffffff;
643 SetLastError(0xdeadbeef);
644 ret = pSetupGetInfFileListW(dir, INF_STYLE_WIN4, NULL, 0, &outsize);
645 ok(!ret, "expected SetupGetInfFileListW to fail!\n");
646 ok(ERROR_DIRECTORY == GetLastError(),
647 "expected error ERROR_DIRECTORY, got %d\n", GetLastError());
649 /* make the filename look like directory
651 dir[1 + lstrlenW(dir)] = 0;
652 dir[lstrlenW(dir)] = '\\';
653 SetLastError(0xdeadbeef);
654 ret = pSetupGetInfFileListW(dir, INF_STYLE_WIN4, NULL, 0, &outsize);
655 ok(!ret, "expected SetupGetInfFileListW to fail!\n");
656 ok(ERROR_DIRECTORY == GetLastError(),
657 "expected error ERROR_DIRECTORY, got %d\n", GetLastError());
659 /* now check the buffer contents of a valid call
661 *ptr = 0;
662 expected = 3 + strlen(inffile) + strlen(inffile2);
663 ret = pSetupGetInfFileListW(dir, INF_STYLE_WIN4, buffer, MAX_PATH, &outsize);
664 ok(ret, "expected SetupGetInfFileListW to succeed!\n");
665 ok(expected == outsize, "expected required buffersize to be %d, got %d\n",
666 expected, outsize);
667 for(p = buffer; lstrlenW(p) && (outsize > (p - buffer)); p+=lstrlenW(p) + 1)
668 ok(!lstrcmpW(p,inffile2W) || !lstrcmpW(p,inffileW),
669 "unexpected filename %s\n",wine_dbgstr_w(p));
671 /* upper case value
673 create_inf_file(inffile2, inf2);
674 ret = pSetupGetInfFileListW(dir, INF_STYLE_WIN4, buffer, MAX_PATH, &outsize);
675 ok(ret, "expected SetupGetInfFileListW to succeed!\n");
676 ok(expected == outsize, "expected required buffersize to be %d, got %d\n",
677 expected, outsize);
678 for(p = buffer; lstrlenW(p) && (outsize > (p - buffer)); p+=lstrlenW(p) + 1)
679 ok(!lstrcmpW(p,inffile2W) || !lstrcmpW(p,inffileW),
680 "unexpected filename %s\n",wine_dbgstr_w(p));
682 /* signature Windows NT is also inf style win4
684 create_inf_file(inffile2, infNT);
685 expected = 3 + strlen(inffile) + strlen(inffile2);
686 ret = pSetupGetInfFileListW(dir, INF_STYLE_WIN4, buffer, MAX_PATH, &outsize);
687 ok(ret, "expected SetupGetInfFileListW to succeed!\n");
688 ok(expected == outsize, "expected required buffersize to be %d, got %d\n",
689 expected, outsize);
690 for(p = buffer; lstrlenW(p) && (outsize > (p - buffer)); p+=lstrlenW(p) + 1)
691 ok(!lstrcmpW(p,inffile2W) || !lstrcmpW(p,inffileW),
692 "unexpected filename %s\n",wine_dbgstr_w(p));
694 /* old style
696 expected = 2 + strlen(invalid_inf);
697 ret = pSetupGetInfFileListW(dir, INF_STYLE_OLDNT, buffer, MAX_PATH, &outsize);
698 ok(ret, "expected SetupGetInfFileListW to succeed!\n");
699 ok(expected == outsize, "expected required buffersize to be %d, got %d\n",
700 expected, outsize);
701 for(p = buffer; lstrlenW(p) && (outsize > (p - buffer)); p+=lstrlenW(p) + 1)
702 ok(!lstrcmpW(p,invalid_infW), "unexpected filename %s\n",wine_dbgstr_w(p));
704 /* mixed style
706 expected = 4 + strlen(inffile) + strlen(inffile2) + strlen(invalid_inf);
707 ret = pSetupGetInfFileListW(dir, INF_STYLE_OLDNT | INF_STYLE_WIN4, buffer,
708 MAX_PATH, &outsize);
709 ok(ret, "expected SetupGetInfFileListW to succeed!\n");
710 ok(expected == outsize, "expected required buffersize to be %d, got %d\n",
711 expected, outsize);
712 for(p = buffer; lstrlenW(p) && (outsize > (p - buffer)); p+=lstrlenW(p) + 1)
713 ok(!lstrcmpW(p,inffile2W) || !lstrcmpW(p,inffileW) || !lstrcmpW(p,invalid_infW),
714 "unexpected filename %s\n",wine_dbgstr_w(p));
716 DeleteFileA(inffile);
717 DeleteFileA(inffile2);
718 DeleteFileA(invalid_inf);
719 SetCurrentDirectoryA(CURR_DIR);
720 RemoveDirectoryA(dirA);
723 static const char dirid_inf[] = "[Version]\n"
724 "Signature=\"$Chicago$\"\n"
725 "[DefaultInstall]\n"
726 "AddReg=Add.Settings\n"
727 "[Add.Settings]\n"
728 "HKCU,Software\\Wine\\setupapitest,dirid,,%%%i%%\n";
730 static void check_dirid(int dirid, LPCSTR expected)
732 char buffer[sizeof(dirid_inf)+11];
733 char path[MAX_PATH], actual[MAX_PATH];
734 LONG ret;
735 DWORD size, type;
736 HKEY key;
738 sprintf(buffer, dirid_inf, dirid);
740 create_inf_file(inffile, buffer);
742 sprintf(path, "%s\\%s", CURR_DIR, inffile);
743 run_cmdline("DefaultInstall", 128, path);
745 size = sizeof(actual);
746 actual[0] = '\0';
747 ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\setupapitest", &key);
748 if (ret == ERROR_SUCCESS)
750 ret = RegQueryValueExA(key, "dirid", NULL, &type, (BYTE*)&actual, &size);
751 RegCloseKey(key);
752 if (type != REG_SZ)
753 ret = ERROR_FILE_NOT_FOUND;
756 ok(ret == ERROR_SUCCESS, "Failed getting value for dirid %i, err=%d\n", dirid, ret);
757 ok(!strcmp(actual, expected), "Expected path for dirid %i was \"%s\", got \"%s\"\n", dirid, expected, actual);
759 ok_registry(TRUE);
760 ret = DeleteFileA(inffile);
761 ok(ret, "Expected source inf to exist, last error was %d\n", GetLastError());
764 /* Test dirid values */
765 static void test_dirid(void)
767 char expected[MAX_PATH];
769 check_dirid(DIRID_NULL, "");
771 GetWindowsDirectoryA(expected, MAX_PATH);
772 check_dirid(DIRID_WINDOWS, expected);
774 GetSystemDirectoryA(expected, MAX_PATH);
775 check_dirid(DIRID_SYSTEM, expected);
777 strcat(expected, "\\unknown");
778 check_dirid(40, expected);
781 START_TEST(install)
783 HMODULE hsetupapi = GetModuleHandleA("setupapi.dll");
784 char temp_path[MAX_PATH], prev_path[MAX_PATH];
785 DWORD len;
787 GetCurrentDirectoryA(MAX_PATH, prev_path);
788 GetTempPathA(MAX_PATH, temp_path);
789 SetCurrentDirectoryA(temp_path);
791 strcpy(CURR_DIR, temp_path);
792 len = strlen(CURR_DIR);
793 if(len && (CURR_DIR[len - 1] == '\\'))
794 CURR_DIR[len - 1] = 0;
796 pInstallHinfSectionA = (void *)GetProcAddress(hsetupapi, "InstallHinfSectionA");
797 pInstallHinfSectionW = (void *)GetProcAddress(hsetupapi, "InstallHinfSectionW");
798 pSetupGetInfFileListA = (void *)GetProcAddress(hsetupapi, "SetupGetInfFileListA");
799 pSetupGetInfFileListW = (void *)GetProcAddress(hsetupapi, "SetupGetInfFileListW");
801 if (pInstallHinfSectionA)
803 /* Check if pInstallHinfSectionA sets last error or is a stub (as on WinXP) */
804 static const char *minimal_inf = "[Version]\nSignature=\"$Chicago$\"\n";
805 char cmdline[MAX_PATH*2];
806 BOOL ret;
807 create_inf_file(inffile, minimal_inf);
808 sprintf(cmdline, "DefaultInstall 128 %s\\%s", CURR_DIR, inffile);
809 SetLastError(0xdeadbeef);
810 pInstallHinfSectionA(NULL, NULL, cmdline, 0);
811 if (GetLastError() == 0xdeadbeef)
813 skip("InstallHinfSectionA is broken (stub)\n");
814 pInstallHinfSectionA = NULL;
816 ret = DeleteFileA(inffile);
817 ok(ret, "Expected source inf to exist, last error was %d\n", GetLastError());
819 if (!pInstallHinfSectionW && !pInstallHinfSectionA)
820 win_skip("InstallHinfSectionA and InstallHinfSectionW are not available\n");
821 else
823 /* Set CBT hook to disallow MessageBox creation in current thread */
824 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
825 assert(hhook != 0);
827 test_cmdline();
828 test_registry();
829 test_install_svc_from();
830 test_driver_install();
831 test_dirid();
833 UnhookWindowsHookEx(hhook);
835 /* We have to run this test after the CBT hook is disabled because
836 ProfileItems needs to create a window on Windows XP. */
837 test_profile_items();
840 test_inffilelist();
841 test_inffilelistA();
843 SetCurrentDirectoryA(prev_path);