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_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 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 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 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 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 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 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 */ 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 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