1 /* 2 * Advpack file functions 3 * 4 * Copyright 2006 James Hawkins 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 "advpack_private.h" 22 23 #include <winver.h> 24 #include <fdi.h> 25 26 /* converts an ansi double null-terminated list to a unicode list */ 27 static LPWSTR ansi_to_unicode_list(LPCSTR ansi_list) 28 { 29 DWORD len, wlen = 0; 30 LPWSTR list; 31 LPCSTR ptr = ansi_list; 32 33 while (*ptr) ptr += lstrlenA(ptr) + 1; 34 len = ptr + 1 - ansi_list; 35 wlen = MultiByteToWideChar(CP_ACP, 0, ansi_list, len, NULL, 0); 36 list = HeapAlloc(GetProcessHeap(), 0, wlen * sizeof(WCHAR)); 37 MultiByteToWideChar(CP_ACP, 0, ansi_list, len, list, wlen); 38 return list; 39 } 40 41 /*********************************************************************** 42 * AddDelBackupEntryA (ADVPACK.@) 43 * 44 * See AddDelBackupEntryW. 45 */ 46 HRESULT WINAPI AddDelBackupEntryA(LPCSTR lpcszFileList, LPCSTR lpcszBackupDir, 47 LPCSTR lpcszBaseName, DWORD dwFlags) 48 { 49 UNICODE_STRING backupdir, basename; 50 LPWSTR filelist; 51 LPCWSTR backup; 52 HRESULT res; 53 54 TRACE("(%s, %s, %s, %d)\n", debugstr_a(lpcszFileList), 55 debugstr_a(lpcszBackupDir), debugstr_a(lpcszBaseName), dwFlags); 56 57 if (lpcszFileList) 58 filelist = ansi_to_unicode_list(lpcszFileList); 59 else 60 filelist = NULL; 61 62 RtlCreateUnicodeStringFromAsciiz(&backupdir, lpcszBackupDir); 63 RtlCreateUnicodeStringFromAsciiz(&basename, lpcszBaseName); 64 65 if (lpcszBackupDir) 66 backup = backupdir.Buffer; 67 else 68 backup = NULL; 69 70 res = AddDelBackupEntryW(filelist, backup, basename.Buffer, dwFlags); 71 72 HeapFree(GetProcessHeap(), 0, filelist); 73 74 RtlFreeUnicodeString(&backupdir); 75 RtlFreeUnicodeString(&basename); 76 77 return res; 78 } 79 80 /*********************************************************************** 81 * AddDelBackupEntryW (ADVPACK.@) 82 * 83 * Either appends the files in the file list to the backup section of 84 * the specified INI, or deletes the entries from the INI file. 85 * 86 * PARAMS 87 * lpcszFileList [I] NULL-separated list of filenames. 88 * lpcszBackupDir [I] Path of the backup directory. 89 * lpcszBaseName [I] Basename of the INI file. 90 * dwFlags [I] AADBE_ADD_ENTRY adds the entries in the file list 91 * to the INI file, while AADBE_DEL_ENTRY removes 92 * the entries from the INI file. 93 * 94 * RETURNS 95 * S_OK in all cases. 96 * 97 * NOTES 98 * If the INI file does not exist before adding entries to it, the file 99 * will be created. 100 * 101 * If lpcszBackupDir is NULL, the INI file is assumed to exist in 102 * c:\windows or created there if it does not exist. 103 */ 104 HRESULT WINAPI AddDelBackupEntryW(LPCWSTR lpcszFileList, LPCWSTR lpcszBackupDir, 105 LPCWSTR lpcszBaseName, DWORD dwFlags) 106 { 107 WCHAR szIniPath[MAX_PATH]; 108 LPCWSTR szString = NULL; 109 110 static const WCHAR szBackupEntry[] = { 111 '-','1',',','0',',','0',',','0',',','0',',','0',',','-','1',0 112 }; 113 114 static const WCHAR backslash[] = {'\\',0}; 115 static const WCHAR ini[] = {'.','i','n','i',0}; 116 static const WCHAR backup[] = {'b','a','c','k','u','p',0}; 117 118 TRACE("(%s, %s, %s, %d)\n", debugstr_w(lpcszFileList), 119 debugstr_w(lpcszBackupDir), debugstr_w(lpcszBaseName), dwFlags); 120 121 if (!lpcszFileList || !*lpcszFileList) 122 return S_OK; 123 124 if (lpcszBackupDir) 125 lstrcpyW(szIniPath, lpcszBackupDir); 126 else 127 GetWindowsDirectoryW(szIniPath, MAX_PATH); 128 129 lstrcatW(szIniPath, backslash); 130 lstrcatW(szIniPath, lpcszBaseName); 131 lstrcatW(szIniPath, ini); 132 133 SetFileAttributesW(szIniPath, FILE_ATTRIBUTE_NORMAL); 134 135 if (dwFlags & AADBE_ADD_ENTRY) 136 szString = szBackupEntry; 137 else if (dwFlags & AADBE_DEL_ENTRY) 138 szString = NULL; 139 140 /* add or delete the INI entries */ 141 while (*lpcszFileList) 142 { 143 WritePrivateProfileStringW(backup, lpcszFileList, szString, szIniPath); 144 lpcszFileList += lstrlenW(lpcszFileList) + 1; 145 } 146 147 /* hide the INI file */ 148 SetFileAttributesW(szIniPath, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN); 149 150 return S_OK; 151 } 152 153 /* FIXME: this is only for the local case, X:\ */ 154 #define ROOT_LENGTH 3 155 156 static UINT CALLBACK pQuietQueueCallback(PVOID Context, UINT Notification, 157 UINT_PTR Param1, UINT_PTR Param2) 158 { 159 return 1; 160 } 161 162 static UINT CALLBACK pQueueCallback(PVOID Context, UINT Notification, 163 UINT_PTR Param1, UINT_PTR Param2) 164 { 165 /* only be verbose for error notifications */ 166 if (!Notification || 167 Notification == SPFILENOTIFY_RENAMEERROR || 168 Notification == SPFILENOTIFY_DELETEERROR || 169 Notification == SPFILENOTIFY_COPYERROR) 170 { 171 return SetupDefaultQueueCallbackW(Context, Notification, 172 Param1, Param2); 173 } 174 175 return 1; 176 } 177 178 /*********************************************************************** 179 * AdvInstallFileA (ADVPACK.@) 180 * 181 * See AdvInstallFileW. 182 */ 183 HRESULT WINAPI AdvInstallFileA(HWND hwnd, LPCSTR lpszSourceDir, LPCSTR lpszSourceFile, 184 LPCSTR lpszDestDir, LPCSTR lpszDestFile, 185 DWORD dwFlags, DWORD dwReserved) 186 { 187 UNICODE_STRING sourcedir, sourcefile; 188 UNICODE_STRING destdir, destfile; 189 HRESULT res; 190 191 TRACE("(%p, %s, %s, %s, %s, %d, %d)\n", hwnd, debugstr_a(lpszSourceDir), 192 debugstr_a(lpszSourceFile), debugstr_a(lpszDestDir), 193 debugstr_a(lpszDestFile), dwFlags, dwReserved); 194 195 if (!lpszSourceDir || !lpszSourceFile || !lpszDestDir) 196 return E_INVALIDARG; 197 198 RtlCreateUnicodeStringFromAsciiz(&sourcedir, lpszSourceDir); 199 RtlCreateUnicodeStringFromAsciiz(&sourcefile, lpszSourceFile); 200 RtlCreateUnicodeStringFromAsciiz(&destdir, lpszDestDir); 201 RtlCreateUnicodeStringFromAsciiz(&destfile, lpszDestFile); 202 203 res = AdvInstallFileW(hwnd, sourcedir.Buffer, sourcefile.Buffer, 204 destdir.Buffer, destfile.Buffer, dwFlags, dwReserved); 205 206 RtlFreeUnicodeString(&sourcedir); 207 RtlFreeUnicodeString(&sourcefile); 208 RtlFreeUnicodeString(&destdir); 209 RtlFreeUnicodeString(&destfile); 210 211 return res; 212 } 213 214 /*********************************************************************** 215 * AdvInstallFileW (ADVPACK.@) 216 * 217 * Copies a file from the source to a destination. 218 * 219 * PARAMS 220 * hwnd [I] Handle to the window used for messages. 221 * lpszSourceDir [I] Source directory. 222 * lpszSourceFile [I] Source filename. 223 * lpszDestDir [I] Destination directory. 224 * lpszDestFile [I] Optional destination filename. 225 * dwFlags [I] See advpub.h. 226 * dwReserved [I] Reserved. Must be 0. 227 * 228 * RETURNS 229 * Success: S_OK. 230 * Failure: E_FAIL. 231 * 232 * NOTES 233 * If lpszDestFile is NULL, the destination filename is the same as 234 * lpszSourceFIle. 235 */ 236 HRESULT WINAPI AdvInstallFileW(HWND hwnd, LPCWSTR lpszSourceDir, LPCWSTR lpszSourceFile, 237 LPCWSTR lpszDestDir, LPCWSTR lpszDestFile, 238 DWORD dwFlags, DWORD dwReserved) 239 { 240 PSP_FILE_CALLBACK_W pFileCallback; 241 LPWSTR szDestFilename; 242 LPCWSTR szPath; 243 WCHAR szRootPath[ROOT_LENGTH]; 244 DWORD dwLen, dwLastError; 245 HSPFILEQ fileQueue; 246 PVOID pContext; 247 248 TRACE("(%p, %s, %s, %s, %s, %d, %d)\n", hwnd, debugstr_w(lpszSourceDir), 249 debugstr_w(lpszSourceFile), debugstr_w(lpszDestDir), 250 debugstr_w(lpszDestFile), dwFlags, dwReserved); 251 252 if (!lpszSourceDir || !lpszSourceFile || !lpszDestDir) 253 return E_INVALIDARG; 254 255 fileQueue = SetupOpenFileQueue(); 256 if (fileQueue == INVALID_HANDLE_VALUE) 257 return HRESULT_FROM_WIN32(GetLastError()); 258 259 pContext = NULL; 260 dwLastError = ERROR_SUCCESS; 261 262 lstrcpynW(szRootPath, lpszSourceDir, ROOT_LENGTH); 263 szPath = lpszSourceDir + ROOT_LENGTH; 264 265 /* use lpszSourceFile as destination filename if lpszDestFile is NULL */ 266 if (lpszDestFile) 267 { 268 dwLen = lstrlenW(lpszDestFile); 269 szDestFilename = HeapAlloc(GetProcessHeap(), 0, (dwLen+1) * sizeof(WCHAR)); 270 lstrcpyW(szDestFilename, lpszDestFile); 271 } 272 else 273 { 274 dwLen = lstrlenW(lpszSourceFile); 275 szDestFilename = HeapAlloc(GetProcessHeap(), 0, (dwLen+1) * sizeof(WCHAR)); 276 lstrcpyW(szDestFilename, lpszSourceFile); 277 } 278 279 /* add the file copy operation to the setup queue */ 280 if (!SetupQueueCopyW(fileQueue, szRootPath, szPath, lpszSourceFile, NULL, 281 NULL, lpszDestDir, szDestFilename, dwFlags)) 282 { 283 dwLastError = GetLastError(); 284 goto done; 285 } 286 287 pContext = SetupInitDefaultQueueCallbackEx(hwnd, INVALID_HANDLE_VALUE, 288 0, 0, NULL); 289 if (!pContext) 290 { 291 dwLastError = GetLastError(); 292 goto done; 293 } 294 295 /* don't output anything for AIF_QUIET */ 296 if (dwFlags & AIF_QUIET) 297 pFileCallback = pQuietQueueCallback; 298 else 299 pFileCallback = pQueueCallback; 300 301 /* perform the file copy */ 302 if (!SetupCommitFileQueueW(hwnd, fileQueue, pFileCallback, pContext)) 303 { 304 dwLastError = GetLastError(); 305 goto done; 306 } 307 308 done: 309 SetupTermDefaultQueueCallback(pContext); 310 SetupCloseFileQueue(fileQueue); 311 312 HeapFree(GetProcessHeap(), 0, szDestFilename); 313 314 return HRESULT_FROM_WIN32(dwLastError); 315 } 316 317 static HRESULT DELNODE_recurse_dirtree(LPWSTR fname, DWORD flags) 318 { 319 DWORD fattrs = GetFileAttributesW(fname); 320 HRESULT ret = E_FAIL; 321 322 static const WCHAR asterisk[] = {'*',0}; 323 static const WCHAR dot[] = {'.',0}; 324 static const WCHAR dotdot[] = {'.','.',0}; 325 326 if (fattrs & FILE_ATTRIBUTE_DIRECTORY) 327 { 328 HANDLE hFindFile; 329 WIN32_FIND_DATAW w32fd; 330 BOOL done = TRUE; 331 int fname_len = lstrlenW(fname); 332 333 /* Generate a path with wildcard suitable for iterating */ 334 if (fname_len && fname[fname_len-1] != '\\') fname[fname_len++] = '\\'; 335 lstrcpyW(fname + fname_len, asterisk); 336 337 if ((hFindFile = FindFirstFileW(fname, &w32fd)) != INVALID_HANDLE_VALUE) 338 { 339 /* Iterate through the files in the directory */ 340 for (done = FALSE; !done; done = !FindNextFileW(hFindFile, &w32fd)) 341 { 342 TRACE("%s\n", debugstr_w(w32fd.cFileName)); 343 if (lstrcmpW(dot, w32fd.cFileName) != 0 && 344 lstrcmpW(dotdot, w32fd.cFileName) != 0) 345 { 346 lstrcpyW(fname + fname_len, w32fd.cFileName); 347 if (DELNODE_recurse_dirtree(fname, flags) != S_OK) 348 { 349 break; /* Failure */ 350 } 351 } 352 } 353 FindClose(hFindFile); 354 } 355 356 /* We're done with this directory, so restore the old path without wildcard */ 357 *(fname + fname_len) = '\0'; 358 359 if (done) 360 { 361 TRACE("%s: directory\n", debugstr_w(fname)); 362 if (SetFileAttributesW(fname, FILE_ATTRIBUTE_NORMAL) && RemoveDirectoryW(fname)) 363 { 364 ret = S_OK; 365 } 366 } 367 } 368 else 369 { 370 TRACE("%s: file\n", debugstr_w(fname)); 371 if (SetFileAttributesW(fname, FILE_ATTRIBUTE_NORMAL) && DeleteFileW(fname)) 372 { 373 ret = S_OK; 374 } 375 } 376 377 return ret; 378 } 379 380 /*********************************************************************** 381 * DelNodeA (ADVPACK.@) 382 * 383 * See DelNodeW. 384 */ 385 HRESULT WINAPI DelNodeA(LPCSTR pszFileOrDirName, DWORD dwFlags) 386 { 387 UNICODE_STRING fileordirname; 388 HRESULT res; 389 390 TRACE("(%s, %d)\n", debugstr_a(pszFileOrDirName), dwFlags); 391 392 RtlCreateUnicodeStringFromAsciiz(&fileordirname, pszFileOrDirName); 393 394 res = DelNodeW(fileordirname.Buffer, dwFlags); 395 396 RtlFreeUnicodeString(&fileordirname); 397 398 return res; 399 } 400 401 /*********************************************************************** 402 * DelNodeW (ADVPACK.@) 403 * 404 * Deletes a file or directory 405 * 406 * PARAMS 407 * pszFileOrDirName [I] Name of file or directory to delete 408 * dwFlags [I] Flags; see include/advpub.h 409 * 410 * RETURNS 411 * Success: S_OK 412 * Failure: E_FAIL 413 * 414 * BUGS 415 * - Ignores flags 416 * - Native version apparently does a lot of checking to make sure 417 * we're not trying to delete a system directory etc. 418 */ 419 HRESULT WINAPI DelNodeW(LPCWSTR pszFileOrDirName, DWORD dwFlags) 420 { 421 WCHAR fname[MAX_PATH]; 422 HRESULT ret = E_FAIL; 423 424 TRACE("(%s, %d)\n", debugstr_w(pszFileOrDirName), dwFlags); 425 426 if (dwFlags) 427 FIXME("Flags ignored!\n"); 428 429 if (pszFileOrDirName && *pszFileOrDirName) 430 { 431 lstrcpyW(fname, pszFileOrDirName); 432 433 /* TODO: Should check for system directory deletion etc. here */ 434 435 ret = DELNODE_recurse_dirtree(fname, dwFlags); 436 } 437 438 return ret; 439 } 440 441 /*********************************************************************** 442 * DelNodeRunDLL32A (ADVPACK.@) 443 * 444 * See DelNodeRunDLL32W. 445 */ 446 HRESULT WINAPI DelNodeRunDLL32A(HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show) 447 { 448 UNICODE_STRING params; 449 HRESULT hr; 450 451 TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_a(cmdline), show); 452 453 RtlCreateUnicodeStringFromAsciiz(¶ms, cmdline); 454 455 hr = DelNodeRunDLL32W(hWnd, hInst, params.Buffer, show); 456 457 RtlFreeUnicodeString(¶ms); 458 459 return hr; 460 } 461 462 /*********************************************************************** 463 * DelNodeRunDLL32W (ADVPACK.@) 464 * 465 * Deletes a file or directory, WinMain style. 466 * 467 * PARAMS 468 * hWnd [I] Handle to the window used for the display. 469 * hInst [I] Instance of the process. 470 * cmdline [I] Contains parameters in the order FileOrDirName,Flags. 471 * show [I] How the window should be shown. 472 * 473 * RETURNS 474 * Success: S_OK. 475 * Failure: E_FAIL. 476 */ 477 HRESULT WINAPI DelNodeRunDLL32W(HWND hWnd, HINSTANCE hInst, LPWSTR cmdline, INT show) 478 { 479 LPWSTR szFilename, szFlags; 480 LPWSTR cmdline_copy, cmdline_ptr; 481 DWORD dwFlags = 0; 482 HRESULT res; 483 484 TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_w(cmdline), show); 485 486 cmdline_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(cmdline) + 1) * sizeof(WCHAR)); 487 cmdline_ptr = cmdline_copy; 488 lstrcpyW(cmdline_copy, cmdline); 489 490 /* get the parameters at indexes 0 and 1 respectively */ 491 szFilename = get_parameter(&cmdline_ptr, ',', TRUE); 492 szFlags = get_parameter(&cmdline_ptr, ',', TRUE); 493 494 if (szFlags) 495 dwFlags = atolW(szFlags); 496 497 res = DelNodeW(szFilename, dwFlags); 498 499 HeapFree(GetProcessHeap(), 0, cmdline_copy); 500 501 return res; 502 } 503 504 /* The following definitions were copied from dlls/cabinet/cabinet.h */ 505 506 /* SESSION Operation */ 507 #define EXTRACT_FILLFILELIST 0x00000001 508 #define EXTRACT_EXTRACTFILES 0x00000002 509 510 struct FILELIST{ 511 LPSTR FileName; 512 struct FILELIST *next; 513 BOOL DoExtract; 514 }; 515 516 typedef struct { 517 INT FileSize; 518 ERF Error; 519 struct FILELIST *FileList; 520 INT FileCount; 521 INT Operation; 522 CHAR Destination[MAX_PATH]; 523 CHAR CurrentFile[MAX_PATH]; 524 CHAR Reserved[MAX_PATH]; 525 struct FILELIST *FilterList; 526 } SESSION; 527 528 static HRESULT (WINAPI *pExtract)(SESSION*, LPCSTR); 529 530 /* removes legal characters before and after file list, and 531 * converts the file list to a NULL-separated list 532 */ 533 static LPSTR convert_file_list(LPCSTR FileList, DWORD *dwNumFiles) 534 { 535 DWORD dwLen; 536 const char *first = FileList; 537 const char *last = FileList + strlen(FileList) - 1; 538 LPSTR szConvertedList, temp; 539 540 /* any number of these chars before the list is OK */ 541 while (first < last && (*first == ' ' || *first == '\t' || *first == ':')) 542 first++; 543 544 /* any number of these chars after the list is OK */ 545 while (last > first && (*last == ' ' || *last == '\t' || *last == ':')) 546 last--; 547 548 if (first == last) 549 return NULL; 550 551 dwLen = last - first + 3; /* room for double-null termination */ 552 szConvertedList = HeapAlloc(GetProcessHeap(), 0, dwLen); 553 lstrcpynA(szConvertedList, first, dwLen - 1); 554 szConvertedList[dwLen - 1] = '\0'; 555 556 /* empty list */ 557 if (!szConvertedList[0]) 558 { 559 HeapFree(GetProcessHeap(), 0, szConvertedList); 560 return NULL; 561 } 562 563 *dwNumFiles = 1; 564 565 /* convert the colons to double-null termination */ 566 temp = szConvertedList; 567 while (*temp) 568 { 569 if (*temp == ':') 570 { 571 *temp = '\0'; 572 (*dwNumFiles)++; 573 } 574 575 temp++; 576 } 577 578 return szConvertedList; 579 } 580 581 static void free_file_node(struct FILELIST *pNode) 582 { 583 HeapFree(GetProcessHeap(), 0, pNode->FileName); 584 HeapFree(GetProcessHeap(), 0, pNode); 585 } 586 587 /* determines whether szFile is in the NULL-separated szFileList */ 588 static BOOL file_in_list(LPCSTR szFile, LPCSTR szFileList) 589 { 590 DWORD dwLen = lstrlenA(szFile); 591 DWORD dwTestLen; 592 593 while (*szFileList) 594 { 595 dwTestLen = lstrlenA(szFileList); 596 597 if (dwTestLen == dwLen) 598 { 599 if (!lstrcmpiA(szFile, szFileList)) 600 return TRUE; 601 } 602 603 szFileList += dwTestLen + 1; 604 } 605 606 return FALSE; 607 } 608 609 610 /* returns the number of files that are in both the linked list and szFileList */ 611 static DWORD fill_file_list(SESSION *session, LPCSTR szCabName, LPCSTR szFileList) 612 { 613 DWORD dwNumFound = 0; 614 struct FILELIST *pNode; 615 616 session->Operation |= EXTRACT_FILLFILELIST; 617 if (pExtract(session, szCabName) != S_OK) 618 { 619 session->Operation &= ~EXTRACT_FILLFILELIST; 620 return -1; 621 } 622 623 pNode = session->FileList; 624 while (pNode) 625 { 626 if (!file_in_list(pNode->FileName, szFileList)) 627 pNode->DoExtract = FALSE; 628 else 629 dwNumFound++; 630 631 pNode = pNode->next; 632 } 633 634 session->Operation &= ~EXTRACT_FILLFILELIST; 635 return dwNumFound; 636 } 637 638 static void free_file_list(SESSION* session) 639 { 640 struct FILELIST *next, *curr = session->FileList; 641 642 while (curr) 643 { 644 next = curr->next; 645 free_file_node(curr); 646 curr = next; 647 } 648 } 649 650 /*********************************************************************** 651 * ExtractFilesA (ADVPACK.@) 652 * 653 * Extracts the specified files from a cab archive into 654 * a destination directory. 655 * 656 * PARAMS 657 * CabName [I] Filename of the cab archive. 658 * ExpandDir [I] Destination directory for the extracted files. 659 * Flags [I] Reserved. 660 * FileList [I] Optional list of files to extract. See NOTES. 661 * LReserved [I] Reserved. Must be NULL. 662 * Reserved [I] Reserved. Must be 0. 663 * 664 * RETURNS 665 * Success: S_OK. 666 * Failure: E_FAIL. 667 * 668 * NOTES 669 * FileList is a colon-separated list of filenames. If FileList is 670 * non-NULL, only the files in the list will be extracted from the 671 * cab file, otherwise all files will be extracted. Any number of 672 * spaces, tabs, or colons can be before or after the list, but 673 * the list itself must only be separated by colons. 674 */ 675 HRESULT WINAPI ExtractFilesA(LPCSTR CabName, LPCSTR ExpandDir, DWORD Flags, 676 LPCSTR FileList, LPVOID LReserved, DWORD Reserved) 677 { 678 SESSION session; 679 HMODULE hCabinet; 680 HRESULT res = S_OK; 681 DWORD dwFileCount = 0; 682 DWORD dwFilesFound = 0; 683 LPSTR szConvertedList = NULL; 684 685 TRACE("(%s, %s, %d, %s, %p, %d)\n", debugstr_a(CabName), debugstr_a(ExpandDir), 686 Flags, debugstr_a(FileList), LReserved, Reserved); 687 688 if (!CabName || !ExpandDir) 689 return E_INVALIDARG; 690 691 if (GetFileAttributesA(ExpandDir) == INVALID_FILE_ATTRIBUTES) 692 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); 693 694 hCabinet = LoadLibraryA("cabinet.dll"); 695 if (!hCabinet) 696 return E_FAIL; 697 698 ZeroMemory(&session, sizeof(SESSION)); 699 700 pExtract = (void *)GetProcAddress(hCabinet, "Extract"); 701 if (!pExtract) 702 { 703 res = E_FAIL; 704 goto done; 705 } 706 707 lstrcpyA(session.Destination, ExpandDir); 708 709 if (FileList) 710 { 711 szConvertedList = convert_file_list(FileList, &dwFileCount); 712 if (!szConvertedList) 713 { 714 res = E_FAIL; 715 goto done; 716 } 717 718 dwFilesFound = fill_file_list(&session, CabName, szConvertedList); 719 if (dwFilesFound != dwFileCount) 720 { 721 res = E_FAIL; 722 goto done; 723 } 724 } 725 else 726 session.Operation |= EXTRACT_FILLFILELIST; 727 728 session.Operation |= EXTRACT_EXTRACTFILES; 729 res = pExtract(&session, CabName); 730 731 done: 732 free_file_list(&session); 733 FreeLibrary(hCabinet); 734 HeapFree(GetProcessHeap(), 0, szConvertedList); 735 736 return res; 737 } 738 739 /*********************************************************************** 740 * ExtractFilesW (ADVPACK.@) 741 * 742 * Extracts the specified files from a cab archive into 743 * a destination directory. 744 * 745 * PARAMS 746 * CabName [I] Filename of the cab archive. 747 * ExpandDir [I] Destination directory for the extracted files. 748 * Flags [I] Reserved. 749 * FileList [I] Optional list of files to extract. See NOTES. 750 * LReserved [I] Reserved. Must be NULL. 751 * Reserved [I] Reserved. Must be 0. 752 * 753 * RETURNS 754 * Success: S_OK. 755 * Failure: E_FAIL. 756 * 757 * NOTES 758 * FileList is a colon-separated list of filenames. If FileList is 759 * non-NULL, only the files in the list will be extracted from the 760 * cab file, otherwise all files will be extracted. Any number of 761 * spaces, tabs, or colons can be before or after the list, but 762 * the list itself must only be separated by colons. 763 * 764 * BUGS 765 * Unimplemented. 766 */ 767 HRESULT WINAPI ExtractFilesW(LPCWSTR CabName, LPCWSTR ExpandDir, DWORD Flags, 768 LPCWSTR FileList, LPVOID LReserved, DWORD Reserved) 769 { 770 char *cab_name = NULL, *expand_dir = NULL, *file_list = NULL; 771 HRESULT hres = S_OK; 772 773 TRACE("(%s, %s, %d, %s, %p, %d)\n", debugstr_w(CabName), debugstr_w(ExpandDir), 774 Flags, debugstr_w(FileList), LReserved, Reserved); 775 776 if(CabName) { 777 cab_name = heap_strdupWtoA(CabName); 778 if(!cab_name) 779 return E_OUTOFMEMORY; 780 } 781 782 if(ExpandDir) { 783 expand_dir = heap_strdupWtoA(ExpandDir); 784 if(!expand_dir) 785 hres = E_OUTOFMEMORY; 786 } 787 788 if(SUCCEEDED(hres) && FileList) { 789 file_list = heap_strdupWtoA(FileList); 790 if(!file_list) 791 hres = E_OUTOFMEMORY; 792 } 793 794 /* cabinet.dll, which does the real job of extracting files, doesn't have UNICODE API, 795 so we need W->A conversion at some point anyway. */ 796 if(SUCCEEDED(hres)) 797 hres = ExtractFilesA(cab_name, expand_dir, Flags, file_list, LReserved, Reserved); 798 799 heap_free(cab_name); 800 heap_free(expand_dir); 801 heap_free(file_list); 802 return hres; 803 } 804 805 /*********************************************************************** 806 * FileSaveMarkNotExistA (ADVPACK.@) 807 * 808 * See FileSaveMarkNotExistW. 809 */ 810 HRESULT WINAPI FileSaveMarkNotExistA(LPSTR pszFileList, LPSTR pszDir, LPSTR pszBaseName) 811 { 812 TRACE("(%s, %s, %s)\n", debugstr_a(pszFileList), 813 debugstr_a(pszDir), debugstr_a(pszBaseName)); 814 815 return AddDelBackupEntryA(pszFileList, pszDir, pszBaseName, AADBE_DEL_ENTRY); 816 } 817 818 /*********************************************************************** 819 * FileSaveMarkNotExistW (ADVPACK.@) 820 * 821 * Marks the files in the file list as not existing so they won't be 822 * backed up during a save. 823 * 824 * PARAMS 825 * pszFileList [I] NULL-separated list of filenames. 826 * pszDir [I] Path of the backup directory. 827 * pszBaseName [I] Basename of the INI file. 828 * 829 * RETURNS 830 * Success: S_OK. 831 * Failure: E_FAIL. 832 */ 833 HRESULT WINAPI FileSaveMarkNotExistW(LPWSTR pszFileList, LPWSTR pszDir, LPWSTR pszBaseName) 834 { 835 TRACE("(%s, %s, %s)\n", debugstr_w(pszFileList), 836 debugstr_w(pszDir), debugstr_w(pszBaseName)); 837 838 return AddDelBackupEntryW(pszFileList, pszDir, pszBaseName, AADBE_DEL_ENTRY); 839 } 840 841 /*********************************************************************** 842 * FileSaveRestoreA (ADVPACK.@) 843 * 844 * See FileSaveRestoreW. 845 */ 846 HRESULT WINAPI FileSaveRestoreA(HWND hDlg, LPSTR pszFileList, LPSTR pszDir, 847 LPSTR pszBaseName, DWORD dwFlags) 848 { 849 UNICODE_STRING filelist, dir, basename; 850 HRESULT hr; 851 852 TRACE("(%p, %s, %s, %s, %d)\n", hDlg, debugstr_a(pszFileList), 853 debugstr_a(pszDir), debugstr_a(pszBaseName), dwFlags); 854 855 RtlCreateUnicodeStringFromAsciiz(&filelist, pszFileList); 856 RtlCreateUnicodeStringFromAsciiz(&dir, pszDir); 857 RtlCreateUnicodeStringFromAsciiz(&basename, pszBaseName); 858 859 hr = FileSaveRestoreW(hDlg, filelist.Buffer, dir.Buffer, 860 basename.Buffer, dwFlags); 861 862 RtlFreeUnicodeString(&filelist); 863 RtlFreeUnicodeString(&dir); 864 RtlFreeUnicodeString(&basename); 865 866 return hr; 867 } 868 869 /*********************************************************************** 870 * FileSaveRestoreW (ADVPACK.@) 871 * 872 * Saves or restores the files in the specified file list. 873 * 874 * PARAMS 875 * hDlg [I] Handle to the dialog used for the display. 876 * pszFileList [I] NULL-separated list of filenames. 877 * pszDir [I] Path of the backup directory. 878 * pszBaseName [I] Basename of the backup files. 879 * dwFlags [I] See advpub.h. 880 * 881 * RETURNS 882 * Success: S_OK. 883 * Failure: E_FAIL. 884 * 885 * NOTES 886 * If pszFileList is NULL on restore, all files will be restored. 887 * 888 * BUGS 889 * Unimplemented. 890 */ 891 HRESULT WINAPI FileSaveRestoreW(HWND hDlg, LPWSTR pszFileList, LPWSTR pszDir, 892 LPWSTR pszBaseName, DWORD dwFlags) 893 { 894 FIXME("(%p, %s, %s, %s, %d) stub\n", hDlg, debugstr_w(pszFileList), 895 debugstr_w(pszDir), debugstr_w(pszBaseName), dwFlags); 896 897 return E_FAIL; 898 } 899 900 /*********************************************************************** 901 * FileSaveRestoreOnINFA (ADVPACK.@) 902 * 903 * See FileSaveRestoreOnINFW. 904 */ 905 HRESULT WINAPI FileSaveRestoreOnINFA(HWND hWnd, LPCSTR pszTitle, LPCSTR pszINF, 906 LPCSTR pszSection, LPCSTR pszBackupDir, 907 LPCSTR pszBaseBackupFile, DWORD dwFlags) 908 { 909 UNICODE_STRING title, inf, section; 910 UNICODE_STRING backupdir, backupfile; 911 HRESULT hr; 912 913 TRACE("(%p, %s, %s, %s, %s, %s, %d)\n", hWnd, debugstr_a(pszTitle), 914 debugstr_a(pszINF), debugstr_a(pszSection), debugstr_a(pszBackupDir), 915 debugstr_a(pszBaseBackupFile), dwFlags); 916 917 RtlCreateUnicodeStringFromAsciiz(&title, pszTitle); 918 RtlCreateUnicodeStringFromAsciiz(&inf, pszINF); 919 RtlCreateUnicodeStringFromAsciiz(§ion, pszSection); 920 RtlCreateUnicodeStringFromAsciiz(&backupdir, pszBackupDir); 921 RtlCreateUnicodeStringFromAsciiz(&backupfile, pszBaseBackupFile); 922 923 hr = FileSaveRestoreOnINFW(hWnd, title.Buffer, inf.Buffer, section.Buffer, 924 backupdir.Buffer, backupfile.Buffer, dwFlags); 925 926 RtlFreeUnicodeString(&title); 927 RtlFreeUnicodeString(&inf); 928 RtlFreeUnicodeString(§ion); 929 RtlFreeUnicodeString(&backupdir); 930 RtlFreeUnicodeString(&backupfile); 931 932 return hr; 933 } 934 935 /*********************************************************************** 936 * FileSaveRestoreOnINFW (ADVPACK.@) 937 * 938 * 939 * PARAMS 940 * hWnd [I] Handle to the window used for the display. 941 * pszTitle [I] Title of the window. 942 * pszINF [I] Fully-qualified INF filename. 943 * pszSection [I] GenInstall INF section name. 944 * pszBackupDir [I] Directory to store the backup file. 945 * pszBaseBackupFile [I] Basename of the backup files. 946 * dwFlags [I] See advpub.h 947 * 948 * RETURNS 949 * Success: S_OK. 950 * Failure: E_FAIL. 951 * 952 * NOTES 953 * If pszSection is NULL, the default section will be used. 954 * 955 * BUGS 956 * Unimplemented. 957 */ 958 HRESULT WINAPI FileSaveRestoreOnINFW(HWND hWnd, LPCWSTR pszTitle, LPCWSTR pszINF, 959 LPCWSTR pszSection, LPCWSTR pszBackupDir, 960 LPCWSTR pszBaseBackupFile, DWORD dwFlags) 961 { 962 FIXME("(%p, %s, %s, %s, %s, %s, %d): stub\n", hWnd, debugstr_w(pszTitle), 963 debugstr_w(pszINF), debugstr_w(pszSection), debugstr_w(pszBackupDir), 964 debugstr_w(pszBaseBackupFile), dwFlags); 965 966 return E_FAIL; 967 } 968 969 /*********************************************************************** 970 * GetVersionFromFileA (ADVPACK.@) 971 * 972 * See GetVersionFromFileExW. 973 */ 974 HRESULT WINAPI GetVersionFromFileA(LPCSTR Filename, LPDWORD MajorVer, 975 LPDWORD MinorVer, BOOL Version ) 976 { 977 TRACE("(%s, %p, %p, %d)\n", debugstr_a(Filename), MajorVer, MinorVer, Version); 978 return GetVersionFromFileExA(Filename, MajorVer, MinorVer, Version); 979 } 980 981 /*********************************************************************** 982 * GetVersionFromFileW (ADVPACK.@) 983 * 984 * See GetVersionFromFileExW. 985 */ 986 HRESULT WINAPI GetVersionFromFileW(LPCWSTR Filename, LPDWORD MajorVer, 987 LPDWORD MinorVer, BOOL Version ) 988 { 989 TRACE("(%s, %p, %p, %d)\n", debugstr_w(Filename), MajorVer, MinorVer, Version); 990 return GetVersionFromFileExW(Filename, MajorVer, MinorVer, Version); 991 } 992 993 /* data for GetVersionFromFileEx */ 994 typedef struct tagLANGANDCODEPAGE 995 { 996 WORD wLanguage; 997 WORD wCodePage; 998 } LANGANDCODEPAGE; 999 1000 /*********************************************************************** 1001 * GetVersionFromFileExA (ADVPACK.@) 1002 * 1003 * See GetVersionFromFileExW. 1004 */ 1005 HRESULT WINAPI GetVersionFromFileExA(LPCSTR lpszFilename, LPDWORD pdwMSVer, 1006 LPDWORD pdwLSVer, BOOL bVersion ) 1007 { 1008 UNICODE_STRING filename; 1009 HRESULT res; 1010 1011 TRACE("(%s, %p, %p, %d)\n", debugstr_a(lpszFilename), 1012 pdwMSVer, pdwLSVer, bVersion); 1013 1014 RtlCreateUnicodeStringFromAsciiz(&filename, lpszFilename); 1015 1016 res = GetVersionFromFileExW(filename.Buffer, pdwMSVer, pdwLSVer, bVersion); 1017 1018 RtlFreeUnicodeString(&filename); 1019 1020 return res; 1021 } 1022 1023 /*********************************************************************** 1024 * GetVersionFromFileExW (ADVPACK.@) 1025 * 1026 * Gets the files version or language information. 1027 * 1028 * PARAMS 1029 * lpszFilename [I] The file to get the info from. 1030 * pdwMSVer [O] Major version. 1031 * pdwLSVer [O] Minor version. 1032 * bVersion [I] Whether to retrieve version or language info. 1033 * 1034 * RETURNS 1035 * Always returns S_OK. 1036 * 1037 * NOTES 1038 * If bVersion is TRUE, version information is retrieved, else 1039 * pdwMSVer gets the language ID and pdwLSVer gets the codepage ID. 1040 */ 1041 HRESULT WINAPI GetVersionFromFileExW(LPCWSTR lpszFilename, LPDWORD pdwMSVer, 1042 LPDWORD pdwLSVer, BOOL bVersion ) 1043 { 1044 VS_FIXEDFILEINFO *pFixedVersionInfo; 1045 LANGANDCODEPAGE *pLangAndCodePage; 1046 DWORD dwHandle, dwInfoSize; 1047 WCHAR szWinDir[MAX_PATH]; 1048 WCHAR szFile[MAX_PATH]; 1049 LPVOID pVersionInfo = NULL; 1050 BOOL bFileCopied = FALSE; 1051 UINT uValueLen; 1052 1053 static const WCHAR backslash[] = {'\\',0}; 1054 static const WCHAR translation[] = { 1055 '\\','V','a','r','F','i','l','e','I','n','f','o', 1056 '\\','T','r','a','n','s','l','a','t','i','o','n',0 1057 }; 1058 1059 TRACE("(%s, %p, %p, %d)\n", debugstr_w(lpszFilename), 1060 pdwMSVer, pdwLSVer, bVersion); 1061 1062 *pdwLSVer = 0; 1063 *pdwMSVer = 0; 1064 1065 lstrcpynW(szFile, lpszFilename, MAX_PATH); 1066 1067 dwInfoSize = GetFileVersionInfoSizeW(szFile, &dwHandle); 1068 if (!dwInfoSize) 1069 { 1070 /* check that the file exists */ 1071 if (GetFileAttributesW(szFile) == INVALID_FILE_ATTRIBUTES) 1072 return S_OK; 1073 1074 /* file exists, but won't be found by GetFileVersionInfoSize, 1075 * so copy it to the temp dir where it will be found. 1076 */ 1077 GetWindowsDirectoryW(szWinDir, MAX_PATH); 1078 GetTempFileNameW(szWinDir, NULL, 0, szFile); 1079 CopyFileW(lpszFilename, szFile, FALSE); 1080 bFileCopied = TRUE; 1081 1082 dwInfoSize = GetFileVersionInfoSizeW(szFile, &dwHandle); 1083 if (!dwInfoSize) 1084 goto done; 1085 } 1086 1087 pVersionInfo = HeapAlloc(GetProcessHeap(), 0, dwInfoSize); 1088 if (!pVersionInfo) 1089 goto done; 1090 1091 if (!GetFileVersionInfoW(szFile, dwHandle, dwInfoSize, pVersionInfo)) 1092 goto done; 1093 1094 if (bVersion) 1095 { 1096 if (!VerQueryValueW(pVersionInfo, backslash, 1097 (LPVOID *)&pFixedVersionInfo, &uValueLen)) 1098 goto done; 1099 1100 if (!uValueLen) 1101 goto done; 1102 1103 *pdwMSVer = pFixedVersionInfo->dwFileVersionMS; 1104 *pdwLSVer = pFixedVersionInfo->dwFileVersionLS; 1105 } 1106 else 1107 { 1108 if (!VerQueryValueW(pVersionInfo, translation, 1109 (LPVOID *)&pLangAndCodePage, &uValueLen)) 1110 goto done; 1111 1112 if (!uValueLen) 1113 goto done; 1114 1115 *pdwMSVer = pLangAndCodePage->wLanguage; 1116 *pdwLSVer = pLangAndCodePage->wCodePage; 1117 } 1118 1119 done: 1120 HeapFree(GetProcessHeap(), 0, pVersionInfo); 1121 1122 if (bFileCopied) 1123 DeleteFileW(szFile); 1124 1125 return S_OK; 1126 } 1127