1 /* 2 * Unit tests for SetupIterateCabinet 3 * 4 * Copyright 2007 Hans Leidekker 5 * Copyright 2010 Andrew Nguyen 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include <stdarg.h> 23 24 #include "windef.h" 25 #include "winbase.h" 26 #include "wingdi.h" 27 #include "winuser.h" 28 #include "winreg.h" 29 #include "setupapi.h" 30 #include "wine/test.h" 31 32 static const BYTE comp_cab_zip_multi[] = { 33 0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 34 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 35 0x00, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 36 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x38, 0xf0, 0x48, 0x20, 0x00, 0x74, 0x72, 0x69, 0x73, 37 0x74, 0x72, 0x61, 0x6d, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 38 0x38, 0xf0, 0x48, 0x20, 0x00, 0x77, 0x69, 0x6e, 0x65, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 39 0x00, 0x00, 0x00, 0x00, 0xd1, 0x38, 0xf0, 0x48, 0x20, 0x00, 0x73, 0x68, 0x61, 0x6e, 0x64, 0x79, 40 0x00, 0x67, 0x2c, 0x03, 0x85, 0x23, 0x00, 0x20, 0x00, 0x43, 0x4b, 0xcb, 0x49, 0x2c, 0x2d, 0x4a, 41 0xcd, 0x4b, 0x4e, 0xe5, 0xe5, 0x2a, 0xcd, 0x4b, 0xce, 0xcf, 0x2d, 0x28, 0x4a, 0x2d, 0x2e, 0x4e, 42 0x4d, 0xe1, 0xe5, 0x2a, 0x2e, 0x49, 0x2d, 0xca, 0x03, 0x8a, 0x02, 0x00 43 }; 44 45 static const WCHAR docW[] = {'d','o','c',0}; 46 47 static void create_source_fileA(LPSTR filename, const BYTE *data, DWORD size) 48 { 49 HANDLE handle; 50 DWORD written; 51 52 handle = CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 53 FILE_ATTRIBUTE_NORMAL, NULL); 54 WriteFile(handle, data, size, &written, NULL); 55 CloseHandle(handle); 56 } 57 58 static void create_source_fileW(LPWSTR filename, const BYTE *data, DWORD size) 59 { 60 HANDLE handle; 61 DWORD written; 62 63 handle = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 64 FILE_ATTRIBUTE_NORMAL, NULL); 65 WriteFile(handle, data, size, &written, NULL); 66 CloseHandle(handle); 67 } 68 69 static UINT CALLBACK dummy_callbackA(PVOID Context, UINT Notification, 70 UINT_PTR Param1, UINT_PTR Param2) 71 { 72 ok(0, "Received unexpected notification (%p, %u, %lu, %lu)\n", Context, 73 Notification, Param1, Param2); 74 return 0; 75 } 76 77 static UINT CALLBACK dummy_callbackW(PVOID Context, UINT Notification, 78 UINT_PTR Param1, UINT_PTR Param2) 79 { 80 ok(0, "Received unexpected notification (%p, %u, %lu, %lu)\n", Context, 81 Notification, Param1, Param2); 82 return 0; 83 } 84 85 static void test_invalid_parametersA(void) 86 { 87 BOOL ret; 88 char source[MAX_PATH], temp[MAX_PATH]; 89 int i; 90 91 const struct 92 { 93 PCSTR CabinetFile; 94 PSP_FILE_CALLBACK_A MsgHandler; 95 DWORD expected_lasterror; 96 int todo_lasterror; 97 } invalid_parameters[] = 98 { 99 {NULL, NULL, ERROR_INVALID_PARAMETER}, 100 {NULL, dummy_callbackA, ERROR_INVALID_PARAMETER}, 101 {"c:\\nonexistent.cab", NULL, ERROR_FILE_NOT_FOUND}, 102 {"c:\\nonexistent.cab", dummy_callbackA, ERROR_FILE_NOT_FOUND}, 103 {source, NULL, ERROR_INVALID_DATA, 1}, 104 {source, dummy_callbackA, ERROR_INVALID_DATA, 1}, 105 }; 106 107 GetTempPathA(sizeof(temp), temp); 108 GetTempFileNameA(temp, "doc", 0, source); 109 110 create_source_fileA(source, NULL, 0); 111 112 for (i = 0; i < ARRAY_SIZE(invalid_parameters); i++) 113 { 114 SetLastError(0xdeadbeef); 115 ret = SetupIterateCabinetA(invalid_parameters[i].CabinetFile, 0, 116 invalid_parameters[i].MsgHandler, NULL); 117 ok(!ret, "[%d] Expected SetupIterateCabinetA to return 0, got %d\n", i, ret); 118 todo_wine_if (invalid_parameters[i].todo_lasterror) 119 ok(GetLastError() == invalid_parameters[i].expected_lasterror, 120 "[%d] Expected GetLastError() to return %u, got %u\n", 121 i, invalid_parameters[i].expected_lasterror, GetLastError()); 122 } 123 124 SetLastError(0xdeadbeef); 125 ret = SetupIterateCabinetA("", 0, NULL, NULL); 126 ok(!ret, "Expected SetupIterateCabinetA to return 0, got %d\n", ret); 127 ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY || 128 GetLastError() == ERROR_FILE_NOT_FOUND, /* Win9x/NT4/Win2k */ 129 "Expected GetLastError() to return ERROR_NOT_ENOUGH_MEMORY, got %u\n", 130 GetLastError()); 131 132 SetLastError(0xdeadbeef); 133 ret = SetupIterateCabinetA("", 0, dummy_callbackA, NULL); 134 ok(!ret, "Expected SetupIterateCabinetA to return 0, got %d\n", ret); 135 ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY || 136 GetLastError() == ERROR_FILE_NOT_FOUND, /* Win9x/NT4/Win2k */ 137 "Expected GetLastError() to return ERROR_NOT_ENOUGH_MEMORY, got %u\n", 138 GetLastError()); 139 140 DeleteFileA(source); 141 } 142 143 static void test_invalid_parametersW(void) 144 { 145 static const WCHAR nonexistentW[] = {'c',':','\\','n','o','n','e','x','i','s','t','e','n','t','.','c','a','b',0}; 146 static const WCHAR emptyW[] = {0}; 147 148 BOOL ret; 149 WCHAR source[MAX_PATH], temp[MAX_PATH]; 150 int i; 151 152 const struct 153 { 154 PCWSTR CabinetFile; 155 PSP_FILE_CALLBACK_W MsgHandler; 156 DWORD expected_lasterror; 157 int todo_lasterror; 158 } invalid_parameters[] = 159 { 160 {nonexistentW, NULL, ERROR_FILE_NOT_FOUND}, 161 {nonexistentW, dummy_callbackW, ERROR_FILE_NOT_FOUND}, 162 {source, NULL, ERROR_INVALID_DATA, 1}, 163 {source, dummy_callbackW, ERROR_INVALID_DATA, 1}, 164 }; 165 166 ret = SetupIterateCabinetW(NULL, 0, NULL, NULL); 167 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 168 { 169 win_skip("SetupIterateCabinetW is not available\n"); 170 return; 171 } 172 173 GetTempPathW(ARRAY_SIZE(temp), temp); 174 GetTempFileNameW(temp, docW, 0, source); 175 176 create_source_fileW(source, NULL, 0); 177 178 for (i = 0; i < ARRAY_SIZE(invalid_parameters); i++) 179 { 180 SetLastError(0xdeadbeef); 181 ret = SetupIterateCabinetW(invalid_parameters[i].CabinetFile, 0, 182 invalid_parameters[i].MsgHandler, NULL); 183 ok(!ret, "[%d] Expected SetupIterateCabinetW to return 0, got %d\n", i, ret); 184 todo_wine_if (invalid_parameters[i].todo_lasterror) 185 ok(GetLastError() == invalid_parameters[i].expected_lasterror, 186 "[%d] Expected GetLastError() to return %u, got %u\n", 187 i, invalid_parameters[i].expected_lasterror, GetLastError()); 188 } 189 190 SetLastError(0xdeadbeef); 191 ret = SetupIterateCabinetW(NULL, 0, NULL, NULL); 192 ok(!ret, "Expected SetupIterateCabinetW to return 0, got %d\n", ret); 193 ok(GetLastError() == ERROR_INVALID_PARAMETER || 194 GetLastError() == ERROR_NOT_ENOUGH_MEMORY, /* Vista/Win2k8 */ 195 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", 196 GetLastError()); 197 198 SetLastError(0xdeadbeef); 199 ret = SetupIterateCabinetW(NULL, 0, dummy_callbackW, NULL); 200 ok(!ret, "Expected SetupIterateCabinetW to return 0, got %d\n", ret); 201 ok(GetLastError() == ERROR_INVALID_PARAMETER || 202 GetLastError() == ERROR_NOT_ENOUGH_MEMORY, /* Vista/Win2k8 */ 203 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n", 204 GetLastError()); 205 206 SetLastError(0xdeadbeef); 207 ret = SetupIterateCabinetW(emptyW, 0, NULL, NULL); 208 ok(!ret, "Expected SetupIterateCabinetW to return 0, got %d\n", ret); 209 ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY || 210 GetLastError() == ERROR_FILE_NOT_FOUND, /* NT4/Win2k */ 211 "Expected GetLastError() to return ERROR_NOT_ENOUGH_MEMORY, got %u\n", 212 GetLastError()); 213 214 SetLastError(0xdeadbeef); 215 ret = SetupIterateCabinetW(emptyW, 0, dummy_callbackW, NULL); 216 ok(!ret, "Expected SetupIterateCabinetW to return 0, got %d\n", ret); 217 ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY || 218 GetLastError() == ERROR_FILE_NOT_FOUND, /* NT4/Win2k */ 219 "Expected GetLastError() to return ERROR_NOT_ENOUGH_MEMORY, got %u\n", 220 GetLastError()); 221 222 DeleteFileW(source); 223 } 224 225 static UINT CALLBACK crash_callbackA(PVOID Context, UINT Notification, 226 UINT_PTR Param1, UINT_PTR Param2) 227 { 228 *(volatile char*)0 = 2; 229 return 0; 230 } 231 232 static UINT CALLBACK crash_callbackW(PVOID Context, UINT Notification, 233 UINT_PTR Param1, UINT_PTR Param2) 234 { 235 *(volatile char*)0 = 2; 236 return 0; 237 } 238 239 static void test_invalid_callbackA(void) 240 { 241 BOOL ret; 242 char source[MAX_PATH], temp[MAX_PATH]; 243 244 GetTempPathA(sizeof(temp), temp); 245 GetTempFileNameA(temp, "doc", 0, source); 246 247 create_source_fileA(source, comp_cab_zip_multi, sizeof(comp_cab_zip_multi)); 248 249 SetLastError(0xdeadbeef); 250 ret = SetupIterateCabinetA(source, 0, NULL, NULL); 251 ok(!ret, "Expected SetupIterateCabinetA to return 0, got %d\n", ret); 252 ok(GetLastError() == ERROR_INVALID_DATA, 253 "Expected GetLastError() to return ERROR_INVALID_DATA, got %u\n", 254 GetLastError()); 255 256 SetLastError(0xdeadbeef); 257 ret = SetupIterateCabinetA(source, 0, crash_callbackA, NULL); 258 ok(!ret, "Expected SetupIterateCabinetA to return 0, got %d\n", ret); 259 ok(GetLastError() == ERROR_INVALID_DATA, 260 "Expected GetLastError() to return ERROR_INVALID_DATA, got %u\n", 261 GetLastError()); 262 263 DeleteFileA(source); 264 } 265 266 static void test_invalid_callbackW(void) 267 { 268 BOOL ret; 269 WCHAR source[MAX_PATH], temp[MAX_PATH]; 270 271 ret = SetupIterateCabinetW(NULL, 0, NULL, NULL); 272 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 273 { 274 win_skip("SetupIterateCabinetW is not available\n"); 275 return; 276 } 277 278 GetTempPathW(ARRAY_SIZE(temp), temp); 279 GetTempFileNameW(temp, docW, 0, source); 280 281 create_source_fileW(source, comp_cab_zip_multi, sizeof(comp_cab_zip_multi)); 282 283 SetLastError(0xdeadbeef); 284 ret = SetupIterateCabinetW(source, 0, NULL, NULL); 285 ok(!ret, "Expected SetupIterateCabinetW to return 0, got %d\n", ret); 286 ok(GetLastError() == ERROR_INVALID_DATA, 287 "Expected GetLastError() to return ERROR_INVALID_DATA, got %u\n", 288 GetLastError()); 289 290 SetLastError(0xdeadbeef); 291 ret = SetupIterateCabinetW(source, 0, crash_callbackW, NULL); 292 ok(!ret, "Expected SetupIterateCabinetW to return 0, got %d\n", ret); 293 ok(GetLastError() == ERROR_INVALID_DATA, 294 "Expected GetLastError() to return ERROR_INVALID_DATA, got %u\n", 295 GetLastError()); 296 297 DeleteFileW(source); 298 } 299 300 static const char *expected_files[] = {"tristram", "wine", "shandy"}; 301 302 struct contextA 303 { 304 int count; 305 const char *cabinet; 306 const char *target; 307 }; 308 309 static UINT CALLBACK simple_callbackA(PVOID Context, UINT Notification, 310 UINT_PTR Param1, UINT_PTR Param2) 311 { 312 static int index; 313 struct contextA *ctx = Context; 314 315 switch (Notification) 316 { 317 case SPFILENOTIFY_CABINETINFO: 318 { 319 CABINET_INFO_A *info = (CABINET_INFO_A *)Param1; 320 321 ok(!strcmp(info->CabinetFile, ""), 322 "Expected empty CabinetFile, got \"%s\"\n", info->CabinetFile); 323 324 index = 0; 325 return NO_ERROR; 326 } 327 case SPFILENOTIFY_FILEINCABINET: 328 { 329 FILE_IN_CABINET_INFO_A *info = (FILE_IN_CABINET_INFO_A *)Param1; 330 const char *cabinet_file = (const char *)Param2; 331 332 ctx->count++; 333 334 if (index < ARRAY_SIZE(expected_files)) 335 { 336 ok(!strcmp(expected_files[index], info->NameInCabinet), 337 "[%d] Expected file \"%s\", got \"%s\"\n", 338 index, expected_files[index], info->NameInCabinet); 339 ok(!strcmp(ctx->cabinet, cabinet_file), 340 "[%d] Expected cabinet \"%s\", got \"%s\"\n", 341 index, ctx->cabinet, cabinet_file); 342 343 strcpy(info->FullTargetName, ctx->target); 344 return FILEOP_DOIT; 345 } 346 else 347 { 348 ok(0, "Unexpectedly enumerated more than number of files in cabinet, index = %d\n", index); 349 return FILEOP_ABORT; 350 } 351 } 352 case SPFILENOTIFY_FILEEXTRACTED: 353 { 354 FILEPATHS_A *info = (FILEPATHS_A *)Param1; 355 356 ok(!strcmp(ctx->cabinet, info->Source), 357 "[%d] Expected cabinet \"%s\", got \"%s\"\n", 358 index, ctx->cabinet, info->Source); 359 ok(!strcmp(ctx->target, info->Target), 360 "[%d] Expected target \"%s\", got \"%s\"\n", 361 index, ctx->target, info->Target); 362 ok(info->Win32Error == 0, 363 "[%d] Expected Win32Error 0, got %u\n", 364 index, info->Win32Error); 365 366 index++; 367 return NO_ERROR; 368 } 369 default: 370 return NO_ERROR; 371 } 372 } 373 374 static void test_simple_enumerationA(void) 375 { 376 BOOL ret; 377 char source[MAX_PATH], temp[MAX_PATH]; 378 char target[MAX_PATH]; 379 struct contextA ctx; 380 381 GetTempPathA(sizeof(temp), temp); 382 GetTempFileNameA(temp, "doc", 0, source); 383 GetTempFileNameA(temp, "doc", 0, target); 384 385 create_source_fileA(source, comp_cab_zip_multi, sizeof(comp_cab_zip_multi)); 386 387 ctx.count = 0; 388 ctx.cabinet = source; 389 ctx.target = target; 390 ret = SetupIterateCabinetA(source, 0, simple_callbackA, &ctx); 391 ok(ret == 1, "Expected SetupIterateCabinetA to return 1, got %d\n", ret); 392 ok(ctx.count == ARRAY_SIZE(expected_files), "Unexpectedly enumerated %d files\n", ctx.count); 393 394 DeleteFileA(source); 395 DeleteFileA(target); 396 } 397 398 static const WCHAR tristramW[] = {'t','r','i','s','t','r','a','m',0}; 399 static const WCHAR wineW[] = {'w','i','n','e',0}; 400 static const WCHAR shandyW[] = {'s','h','a','n','d','y',0}; 401 static const WCHAR *expected_filesW[] = {tristramW, wineW, shandyW}; 402 403 struct contextW 404 { 405 int count; 406 const WCHAR *cabinet; 407 const WCHAR *target; 408 }; 409 410 static UINT CALLBACK simple_callbackW(PVOID Context, UINT Notification, 411 UINT_PTR Param1, UINT_PTR Param2) 412 { 413 static const WCHAR emptyW[] = {0}; 414 static int index; 415 struct contextW *ctx = Context; 416 417 switch (Notification) 418 { 419 case SPFILENOTIFY_CABINETINFO: 420 { 421 CABINET_INFO_W *info = (CABINET_INFO_W *)Param1; 422 423 ok(!lstrcmpW(info->CabinetFile, emptyW), 424 "Expected empty CabinetFile, got %s\n", wine_dbgstr_w(info->CabinetFile)); 425 426 index = 0; 427 return NO_ERROR; 428 } 429 case SPFILENOTIFY_FILEINCABINET: 430 { 431 FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)Param1; 432 const WCHAR *cabinet_file = (const WCHAR *)Param2; 433 434 ctx->count++; 435 436 if (index < ARRAY_SIZE(expected_filesW)) 437 { 438 ok(!lstrcmpW(expected_filesW[index], info->NameInCabinet), 439 "[%d] Expected file %s, got %s\n", 440 index, wine_dbgstr_w(expected_filesW[index]), wine_dbgstr_w(info->NameInCabinet)); 441 ok(!lstrcmpW(ctx->cabinet, cabinet_file), 442 "[%d] Expected cabinet %s, got %s\n", 443 index, wine_dbgstr_w(ctx->cabinet), wine_dbgstr_w(cabinet_file)); 444 445 lstrcpyW(info->FullTargetName, ctx->target); 446 return FILEOP_DOIT; 447 } 448 else 449 { 450 ok(0, "Unexpectedly enumerated more than number of files in cabinet, index = %d\n", index); 451 return FILEOP_ABORT; 452 } 453 } 454 case SPFILENOTIFY_FILEEXTRACTED: 455 { 456 FILEPATHS_W *info = (FILEPATHS_W *)Param1; 457 458 ok(!lstrcmpW(ctx->cabinet, info->Source), 459 "[%d] Expected cabinet %s, got %s\n", 460 index, wine_dbgstr_w(ctx->cabinet), wine_dbgstr_w(info->Source)); 461 ok(!lstrcmpW(ctx->target, info->Target), 462 "[%d] Expected target %s, got %s\n", 463 index, wine_dbgstr_w(ctx->target), wine_dbgstr_w(info->Target)); 464 ok(info->Win32Error == 0, 465 "[%d] Expected Win32Error 0, got %u\n", 466 index, info->Win32Error); 467 468 index++; 469 return NO_ERROR; 470 } 471 default: 472 return NO_ERROR; 473 } 474 } 475 476 static void test_simple_enumerationW(void) 477 { 478 BOOL ret; 479 WCHAR source[MAX_PATH], temp[MAX_PATH]; 480 WCHAR target[MAX_PATH]; 481 struct contextW ctx; 482 483 ret = SetupIterateCabinetW(NULL, 0, NULL, NULL); 484 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 485 { 486 win_skip("SetupIterateCabinetW is not available\n"); 487 return; 488 } 489 490 GetTempPathW(ARRAY_SIZE(temp), temp); 491 GetTempFileNameW(temp, docW, 0, source); 492 GetTempFileNameW(temp, docW, 0, target); 493 494 create_source_fileW(source, comp_cab_zip_multi, sizeof(comp_cab_zip_multi)); 495 496 ctx.count = 0; 497 ctx.cabinet = source; 498 ctx.target = target; 499 ret = SetupIterateCabinetW(source, 0, simple_callbackW, &ctx); 500 ok(ret == 1, "Expected SetupIterateCabinetW to return 1, got %d\n", ret); 501 ok(ctx.count == ARRAY_SIZE(expected_files), "Unexpectedly enumerated %d files\n", ctx.count); 502 503 DeleteFileW(source); 504 DeleteFileW(target); 505 } 506 507 START_TEST(setupcab) 508 { 509 test_invalid_parametersA(); 510 test_invalid_parametersW(); 511 512 /* Tests crash on NT4/Win9x/Win2k and Wine. */ 513 if (0) 514 { 515 test_invalid_callbackA(); 516 test_invalid_callbackW(); 517 } 518 519 test_simple_enumerationA(); 520 test_simple_enumerationW(); 521 } 522