2 * Advpack file functions
4 * Copyright 2006 James Hawkins
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
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
34 #include "advpack_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(advpack);
38 /* converts an ansi double null-terminated list to a unicode list */
39 static LPWSTR ansi_to_unicode_list(LPCSTR ansi_list)
43 LPCSTR ptr = ansi_list;
45 while (*ptr) ptr += lstrlenA(ptr) + 1;
46 len = ptr + 1 - ansi_list;
47 wlen = MultiByteToWideChar(CP_ACP, 0, ansi_list, len, NULL, 0);
48 list = HeapAlloc(GetProcessHeap(), 0, wlen * sizeof(WCHAR));
49 MultiByteToWideChar(CP_ACP, 0, ansi_list, len, list, wlen);
53 /***********************************************************************
54 * AddDelBackupEntryA (ADVPACK.@)
56 * See AddDelBackupEntryW.
58 HRESULT WINAPI AddDelBackupEntryA(LPCSTR lpcszFileList, LPCSTR lpcszBackupDir,
59 LPCSTR lpcszBaseName, DWORD dwFlags)
61 UNICODE_STRING backupdir, basename;
62 LPWSTR filelist, backup;
65 TRACE("(%s, %s, %s, %ld)\n", debugstr_a(lpcszFileList),
66 debugstr_a(lpcszBackupDir), debugstr_a(lpcszBaseName), dwFlags);
69 filelist = ansi_to_unicode_list(lpcszFileList);
73 RtlCreateUnicodeStringFromAsciiz(&backupdir, lpcszBackupDir);
74 RtlCreateUnicodeStringFromAsciiz(&basename, lpcszBaseName);
77 backup = backupdir.Buffer;
81 res = AddDelBackupEntryW(filelist, backup, basename.Buffer, dwFlags);
83 HeapFree(GetProcessHeap(), 0, filelist);
85 RtlFreeUnicodeString(&backupdir);
86 RtlFreeUnicodeString(&basename);
91 /***********************************************************************
92 * AddDelBackupEntryW (ADVPACK.@)
94 * Either appends the files in the file list to the backup section of
95 * the specified INI, or deletes the entries from the INI file.
98 * lpcszFileList [I] NULL-separated list of filenames.
99 * lpcszBackupDir [I] Path of the backup directory.
100 * lpcszBaseName [I] Basename of the INI file.
101 * dwFlags [I] AADBE_ADD_ENTRY adds the entries in the file list
102 * to the INI file, while AADBE_DEL_ENTRY removes
103 * the entries from the INI file.
109 * If the INI file does not exist before adding entries to it, the file
112 * If lpcszBackupDir is NULL, the INI file is assumed to exist in
113 * c:\windows or created there if it does not exist.
115 HRESULT WINAPI AddDelBackupEntryW(LPCWSTR lpcszFileList, LPCWSTR lpcszBackupDir,
116 LPCWSTR lpcszBaseName, DWORD dwFlags)
118 WCHAR szIniPath[MAX_PATH];
119 LPCWSTR szString = NULL;
121 static const WCHAR szBackupEntry[] = {
122 '-','1',',','0',',','0',',','0',',','0',',','0',',','-','1',0
125 static const WCHAR backslash[] = {'\\',0};
126 static const WCHAR ini[] = {'.','i','n','i',0};
127 static const WCHAR backup[] = {'b','a','c','k','u','p',0};
129 TRACE("(%s, %s, %s, %ld)\n", debugstr_w(lpcszFileList),
130 debugstr_w(lpcszBackupDir), debugstr_w(lpcszBaseName), dwFlags);
132 if (!lpcszFileList || !*lpcszFileList)
136 lstrcpyW(szIniPath, lpcszBackupDir);
138 GetWindowsDirectoryW(szIniPath, MAX_PATH);
140 lstrcatW(szIniPath, backslash);
141 lstrcatW(szIniPath, lpcszBaseName);
142 lstrcatW(szIniPath, ini);
144 SetFileAttributesW(szIniPath, FILE_ATTRIBUTE_NORMAL);
146 if (dwFlags & AADBE_ADD_ENTRY)
147 szString = szBackupEntry;
148 else if (dwFlags & AADBE_DEL_ENTRY)
151 /* add or delete the INI entries */
152 while (*lpcszFileList)
154 WritePrivateProfileStringW(backup, lpcszFileList, szString, szIniPath);
155 lpcszFileList += lstrlenW(lpcszFileList) + 1;
158 /* hide the INI file */
159 SetFileAttributesW(szIniPath, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN);
164 /* FIXME: this is only for the local case, X:\ */
165 #define ROOT_LENGTH 3
167 UINT CALLBACK pQuietQueueCallback(PVOID Context, UINT Notification,
168 UINT_PTR Param1, UINT_PTR Param2)
173 UINT CALLBACK pQueueCallback(PVOID Context, UINT Notification,
174 UINT_PTR Param1, UINT_PTR Param2)
176 /* only be verbose for error notifications */
178 Notification == SPFILENOTIFY_RENAMEERROR ||
179 Notification == SPFILENOTIFY_DELETEERROR ||
180 Notification == SPFILENOTIFY_COPYERROR)
182 return SetupDefaultQueueCallbackW(Context, Notification,
189 /***********************************************************************
190 * AdvInstallFileA (ADVPACK.@)
192 * See AdvInstallFileW.
194 HRESULT WINAPI AdvInstallFileA(HWND hwnd, LPCSTR lpszSourceDir, LPCSTR lpszSourceFile,
195 LPCSTR lpszDestDir, LPCSTR lpszDestFile,
196 DWORD dwFlags, DWORD dwReserved)
198 UNICODE_STRING sourcedir, sourcefile;
199 UNICODE_STRING destdir, destfile;
202 TRACE("(%p, %s, %s, %s, %s, %ld, %ld)\n", hwnd, debugstr_a(lpszSourceDir),
203 debugstr_a(lpszSourceFile), debugstr_a(lpszDestDir),
204 debugstr_a(lpszDestFile), dwFlags, dwReserved);
206 if (!lpszSourceDir || !lpszSourceFile || !lpszDestDir)
209 RtlCreateUnicodeStringFromAsciiz(&sourcedir, lpszSourceDir);
210 RtlCreateUnicodeStringFromAsciiz(&sourcefile, lpszSourceFile);
211 RtlCreateUnicodeStringFromAsciiz(&destdir, lpszDestDir);
212 RtlCreateUnicodeStringFromAsciiz(&destfile, lpszDestFile);
214 res = AdvInstallFileW(hwnd, sourcedir.Buffer, sourcefile.Buffer,
215 destdir.Buffer, destfile.Buffer, dwFlags, dwReserved);
217 RtlFreeUnicodeString(&sourcedir);
218 RtlFreeUnicodeString(&sourcefile);
219 RtlFreeUnicodeString(&destdir);
220 RtlFreeUnicodeString(&destfile);
225 /***********************************************************************
226 * AdvInstallFileW (ADVPACK.@)
228 * Copies a file from the source to a destination.
231 * hwnd [I] Handle to the window used for messages.
232 * lpszSourceDir [I] Source directory.
233 * lpszSourceFile [I] Source filename.
234 * lpszDestDir [I] Destination directory.
235 * lpszDestFile [I] Optional destination filename.
236 * dwFlags [I] See advpub.h.
237 * dwReserved [I] Reserved. Must be 0.
244 * If lpszDestFile is NULL, the destination filename is the same as
247 HRESULT WINAPI AdvInstallFileW(HWND hwnd, LPCWSTR lpszSourceDir, LPCWSTR lpszSourceFile,
248 LPCWSTR lpszDestDir, LPCWSTR lpszDestFile,
249 DWORD dwFlags, DWORD dwReserved)
251 PSP_FILE_CALLBACK_W pFileCallback;
252 LPWSTR szDestFilename;
254 WCHAR szRootPath[ROOT_LENGTH];
255 DWORD dwLen, dwLastError;
259 TRACE("(%p, %s, %s, %s, %s, %ld, %ld)\n", hwnd, debugstr_w(lpszSourceDir),
260 debugstr_w(lpszSourceFile), debugstr_w(lpszDestDir),
261 debugstr_w(lpszDestFile), dwFlags, dwReserved);
263 if (!lpszSourceDir || !lpszSourceFile || !lpszDestDir)
266 fileQueue = SetupOpenFileQueue();
267 if (fileQueue == INVALID_HANDLE_VALUE)
268 return HRESULT_FROM_WIN32(GetLastError());
271 dwLastError = ERROR_SUCCESS;
273 lstrcpynW(szRootPath, lpszSourceDir, ROOT_LENGTH);
274 szPath = lpszSourceDir + ROOT_LENGTH;
276 /* use lpszSourceFile as destination filename if lpszDestFile is NULL */
279 dwLen = lstrlenW(lpszDestFile);
280 szDestFilename = HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(WCHAR));
281 lstrcpyW(szDestFilename, lpszDestFile);
285 dwLen = lstrlenW(lpszSourceFile);
286 szDestFilename = HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(WCHAR));
287 lstrcpyW(szDestFilename, lpszSourceFile);
290 /* add the file copy operation to the setup queue */
291 if (!SetupQueueCopyW(fileQueue, szRootPath, szPath, lpszSourceFile, NULL,
292 NULL, lpszDestDir, szDestFilename, dwFlags))
294 dwLastError = GetLastError();
298 pContext = SetupInitDefaultQueueCallbackEx(hwnd, INVALID_HANDLE_VALUE,
302 dwLastError = GetLastError();
306 /* don't output anything for AIF_QUIET */
307 if (dwFlags & AIF_QUIET)
308 pFileCallback = pQuietQueueCallback;
310 pFileCallback = pQueueCallback;
312 /* perform the file copy */
313 if (!SetupCommitFileQueueW(hwnd, fileQueue, pFileCallback, pContext))
315 dwLastError = GetLastError();
320 SetupTermDefaultQueueCallback(pContext);
321 SetupCloseFileQueue(fileQueue);
323 HeapFree(GetProcessHeap(), 0, szDestFilename);
325 return HRESULT_FROM_WIN32(dwLastError);
328 static HRESULT DELNODE_recurse_dirtree(LPWSTR fname, DWORD flags)
330 DWORD fattrs = GetFileAttributesW(fname);
331 HRESULT ret = E_FAIL;
333 static const WCHAR backslash[] = {'\\',0};
334 static const WCHAR asterisk[] = {'*',0};
335 static const WCHAR dot[] = {'.',0};
336 static const WCHAR dotdot[] = {'.','.',0};
338 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
341 WIN32_FIND_DATAW w32fd;
343 int fname_len = lstrlenW(fname);
345 /* Generate a path with wildcard suitable for iterating */
346 if (lstrcmpW(CharPrevW(fname, fname + fname_len), backslash))
348 lstrcpyW(fname + fname_len, backslash);
351 lstrcpyW(fname + fname_len, asterisk);
353 if ((hFindFile = FindFirstFileW(fname, &w32fd)) != INVALID_HANDLE_VALUE)
355 /* Iterate through the files in the directory */
356 for (done = FALSE; !done; done = !FindNextFileW(hFindFile, &w32fd))
358 TRACE("%s\n", debugstr_w(w32fd.cFileName));
359 if (lstrcmpW(dot, w32fd.cFileName) != 0 &&
360 lstrcmpW(dotdot, w32fd.cFileName) != 0)
362 lstrcpyW(fname + fname_len, w32fd.cFileName);
363 if (DELNODE_recurse_dirtree(fname, flags) != S_OK)
369 FindClose(hFindFile);
372 /* We're done with this directory, so restore the old path without wildcard */
373 *(fname + fname_len) = '\0';
377 TRACE("%s: directory\n", debugstr_w(fname));
378 if (SetFileAttributesW(fname, FILE_ATTRIBUTE_NORMAL) && RemoveDirectoryW(fname))
386 TRACE("%s: file\n", debugstr_w(fname));
387 if (SetFileAttributesW(fname, FILE_ATTRIBUTE_NORMAL) && DeleteFileW(fname))
396 /***********************************************************************
397 * DelNodeA (ADVPACK.@)
401 HRESULT WINAPI DelNodeA(LPCSTR pszFileOrDirName, DWORD dwFlags)
403 UNICODE_STRING fileordirname;
406 TRACE("(%s, %ld)\n", debugstr_a(pszFileOrDirName), dwFlags);
408 RtlCreateUnicodeStringFromAsciiz(&fileordirname, pszFileOrDirName);
410 res = DelNodeW(fileordirname.Buffer, dwFlags);
412 RtlFreeUnicodeString(&fileordirname);
417 /***********************************************************************
418 * DelNodeW (ADVPACK.@)
420 * Deletes a file or directory
423 * pszFileOrDirName [I] Name of file or directory to delete
424 * dwFlags [I] Flags; see include/advpub.h
432 * - Native version apparently does a lot of checking to make sure
433 * we're not trying to delete a system directory etc.
435 HRESULT WINAPI DelNodeW(LPCWSTR pszFileOrDirName, DWORD dwFlags)
437 WCHAR fname[MAX_PATH];
438 HRESULT ret = E_FAIL;
440 TRACE("(%s, %ld)\n", debugstr_w(pszFileOrDirName), dwFlags);
443 FIXME("Flags ignored!\n");
445 if (pszFileOrDirName && *pszFileOrDirName)
447 lstrcpyW(fname, pszFileOrDirName);
449 /* TODO: Should check for system directory deletion etc. here */
451 ret = DELNODE_recurse_dirtree(fname, dwFlags);
457 /***********************************************************************
458 * DelNodeRunDLL32A (ADVPACK.@)
460 * See DelNodeRunDLL32W.
462 HRESULT WINAPI DelNodeRunDLL32A(HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show)
464 UNICODE_STRING params;
467 TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_a(cmdline), show);
469 RtlCreateUnicodeStringFromAsciiz(¶ms, cmdline);
471 hr = DelNodeRunDLL32W(hWnd, hInst, params.Buffer, show);
473 RtlFreeUnicodeString(¶ms);
478 /***********************************************************************
479 * DelNodeRunDLL32W (ADVPACK.@)
481 * Deletes a file or directory, WinMain style.
484 * hWnd [I] Handle to the window used for the display.
485 * hInst [I] Instance of the process.
486 * cmdline [I] Contains parameters in the order FileOrDirName,Flags.
487 * show [I] How the window should be shown.
493 HRESULT WINAPI DelNodeRunDLL32W(HWND hWnd, HINSTANCE hInst, LPWSTR cmdline, INT show)
495 LPWSTR szFilename, szFlags;
496 LPWSTR cmdline_copy, cmdline_ptr;
500 TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_w(cmdline), show);
502 cmdline_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(cmdline) + 1) * sizeof(WCHAR));
503 cmdline_ptr = cmdline_copy;
504 lstrcpyW(cmdline_copy, cmdline);
506 /* get the parameters at indexes 0 and 1 respectively */
507 szFilename = get_parameter(&cmdline_ptr, ',');
508 szFlags = get_parameter(&cmdline_ptr, ',');
511 dwFlags = atolW(szFlags);
513 res = DelNodeW(szFilename, dwFlags);
515 HeapFree(GetProcessHeap(), 0, cmdline_copy);
520 /* The following defintions were copied from dlls/cabinet/cabinet.h */
522 /* EXTRACTdest flags */
523 #define EXTRACT_FILLFILELIST 0x00000001
524 #define EXTRACT_EXTRACTFILES 0x00000002
526 struct ExtractFileList {
528 struct ExtractFileList *next;
529 BOOL unknown; /* always 1L */
532 /* the first parameter of the function Extract */
534 long result1; /* 0x000 */
535 long unknown1[3]; /* 0x004 */
536 struct ExtractFileList *filelist; /* 0x010 */
537 long filecount; /* 0x014 */
538 DWORD flags; /* 0x018 */
539 char directory[0x104]; /* 0x01c */
540 char lastfile[0x20c]; /* 0x120 */
543 static HRESULT (WINAPI *pExtract)(EXTRACTdest*, LPCSTR);
545 /* removes legal characters before and after file list, and
546 * converts the file list to a NULL-separated list
548 static LPSTR convert_file_list(LPCSTR FileList, DWORD *dwNumFiles)
551 char *first = (char *)FileList;
552 char *last = (char *)FileList + strlen(FileList) - 1;
553 LPSTR szConvertedList, temp;
555 /* any number of these chars before the list is OK */
556 while (first < last && (*first == ' ' || *first == '\t' || *first == ':'))
559 /* any number of these chars after the list is OK */
560 while (last > first && (*last == ' ' || *last == '\t' || *last == ':'))
566 dwLen = last - first + 3; /* room for double-null termination */
567 szConvertedList = HeapAlloc(GetProcessHeap(), 0, dwLen);
568 lstrcpynA(szConvertedList, first, dwLen - 1);
570 szConvertedList[dwLen - 1] = '\0';
571 szConvertedList[dwLen] = '\0';
574 if (!lstrlenA(szConvertedList))
579 /* convert the colons to double-null termination */
580 temp = szConvertedList;
592 return szConvertedList;
595 static void free_file_node(struct ExtractFileList *pNode)
597 HeapFree(GetProcessHeap(), 0, pNode->filename);
598 HeapFree(GetProcessHeap(), 0, pNode);
601 /* determines whether szFile is in the NULL-separated szFileList */
602 static BOOL file_in_list(LPSTR szFile, LPSTR szFileList)
604 DWORD dwLen = lstrlenA(szFile);
609 dwTestLen = lstrlenA(szFileList);
611 if (dwTestLen == dwLen)
613 if (!lstrcmpiA(szFile, szFileList))
617 szFileList += dwTestLen + 1;
623 /* removes nodes from the linked list that aren't specified in szFileList
624 * returns the number of files that are in both the linked list and szFileList
626 static DWORD fill_file_list(EXTRACTdest *extractDest, LPCSTR szCabName, LPSTR szFileList)
628 DWORD dwNumFound = 0;
629 struct ExtractFileList *pNode;
630 struct ExtractFileList *prev = NULL;
632 extractDest->flags |= EXTRACT_FILLFILELIST;
633 if (pExtract(extractDest, szCabName))
635 extractDest->flags &= ~EXTRACT_FILLFILELIST;
639 pNode = extractDest->filelist;
642 if (file_in_list(pNode->filename, szFileList))
650 prev->next = pNode->next;
651 free_file_node(pNode);
656 extractDest->filelist = pNode->next;
657 free_file_node(pNode);
658 pNode = extractDest->filelist;
662 extractDest->flags &= ~EXTRACT_FILLFILELIST;
666 /***********************************************************************
667 * ExtractFilesA (ADVPACK.@)
669 * Extracts the specified files from a cab archive into
670 * a destination directory.
673 * CabName [I] Filename of the cab archive.
674 * ExpandDir [I] Destination directory for the extracted files.
675 * Flags [I] Reserved.
676 * FileList [I] Optional list of files to extract. See NOTES.
677 * LReserved [I] Reserved. Must be NULL.
678 * Reserved [I] Reserved. Must be 0.
685 * FileList is a colon-separated list of filenames. If FileList is
686 * non-NULL, only the files in the list will be extracted from the
687 * cab file, otherwise all files will be extracted. Any number of
688 * spaces, tabs, or colons can be before or after the list, but
689 * the list itself must only be separated by colons.
691 HRESULT WINAPI ExtractFilesA(LPCSTR CabName, LPCSTR ExpandDir, DWORD Flags,
692 LPCSTR FileList, LPVOID LReserved, DWORD Reserved)
694 EXTRACTdest extractDest;
697 DWORD dwFileCount = 0;
698 DWORD dwFilesFound = 0;
699 LPSTR szConvertedList = NULL;
701 TRACE("(%s, %s, %ld, %s, %p, %ld)\n", debugstr_a(CabName), debugstr_a(ExpandDir),
702 Flags, debugstr_a(FileList), LReserved, Reserved);
704 if (!CabName || !ExpandDir)
707 if (GetFileAttributesA(ExpandDir) == INVALID_FILE_ATTRIBUTES)
708 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
710 hCabinet = LoadLibraryA("cabinet.dll");
714 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
721 ZeroMemory(&extractDest, sizeof(EXTRACTdest));
722 lstrcpyA(extractDest.directory, ExpandDir);
726 szConvertedList = convert_file_list(FileList, &dwFileCount);
727 if (!szConvertedList || dwFileCount == -1)
733 dwFilesFound = fill_file_list(&extractDest, CabName, szConvertedList);
734 if (dwFilesFound != dwFileCount)
741 extractDest.flags |= EXTRACT_FILLFILELIST;
743 extractDest.flags |= EXTRACT_EXTRACTFILES;
744 res = pExtract(&extractDest, CabName);
747 FreeLibrary(hCabinet);
748 HeapFree(GetProcessHeap(), 0, szConvertedList);
753 /***********************************************************************
754 * FileSaveMarkNotExistA (ADVPACK.@)
756 * See FileSaveMarkNotExistW.
758 HRESULT WINAPI FileSaveMarkNotExistA(LPSTR pszFileList, LPSTR pszDir, LPSTR pszBaseName)
760 TRACE("(%s, %s, %s)\n", debugstr_a(pszFileList),
761 debugstr_a(pszDir), debugstr_a(pszBaseName));
763 return AddDelBackupEntryA(pszFileList, pszDir, pszBaseName, AADBE_DEL_ENTRY);
766 /***********************************************************************
767 * FileSaveMarkNotExistW (ADVPACK.@)
769 * Marks the files in the file list as not existing so they won't be
770 * backed up during a save.
773 * pszFileList [I] NULL-separated list of filenames.
774 * pszDir [I] Path of the backup directory.
775 * pszBaseName [I] Basename of the INI file.
781 HRESULT WINAPI FileSaveMarkNotExistW(LPWSTR pszFileList, LPWSTR pszDir, LPWSTR pszBaseName)
783 TRACE("(%s, %s, %s)\n", debugstr_w(pszFileList),
784 debugstr_w(pszDir), debugstr_w(pszBaseName));
786 return AddDelBackupEntryW(pszFileList, pszDir, pszBaseName, AADBE_DEL_ENTRY);
789 /***********************************************************************
790 * FileSaveRestoreA (ADVPACK.@)
792 * See FileSaveRestoreW.
794 HRESULT WINAPI FileSaveRestoreA(HWND hDlg, LPSTR pszFileList, LPSTR pszDir,
795 LPSTR pszBaseName, DWORD dwFlags)
797 UNICODE_STRING filelist, dir, basename;
800 TRACE("(%p, %s, %s, %s, %ld)\n", hDlg, debugstr_a(pszFileList),
801 debugstr_a(pszDir), debugstr_a(pszBaseName), dwFlags);
803 RtlCreateUnicodeStringFromAsciiz(&filelist, pszFileList);
804 RtlCreateUnicodeStringFromAsciiz(&dir, pszDir);
805 RtlCreateUnicodeStringFromAsciiz(&basename, pszBaseName);
807 hr = FileSaveRestoreW(hDlg, filelist.Buffer, dir.Buffer,
808 basename.Buffer, dwFlags);
810 RtlFreeUnicodeString(&filelist);
811 RtlFreeUnicodeString(&dir);
812 RtlFreeUnicodeString(&basename);
817 /***********************************************************************
818 * FileSaveRestoreW (ADVPACK.@)
820 * Saves or restores the files in the specified file list.
823 * hDlg [I] Handle to the dialog used for the display.
824 * pszFileList [I] NULL-separated list of filenames.
825 * pszDir [I] Path of the backup directory.
826 * pszBaseName [I] Basename of the backup files.
827 * dwFlags [I] See advpub.h.
834 * If pszFileList is NULL on restore, all files will be restored.
839 HRESULT WINAPI FileSaveRestoreW(HWND hDlg, LPWSTR pszFileList, LPWSTR pszDir,
840 LPWSTR pszBaseName, DWORD dwFlags)
842 FIXME("(%p, %s, %s, %s, %ld) stub\n", hDlg, debugstr_w(pszFileList),
843 debugstr_w(pszDir), debugstr_w(pszBaseName), dwFlags);
848 /***********************************************************************
849 * FileSaveRestoreOnINFA (ADVPACK.@)
851 * See FileSaveRestoreOnINFW.
853 HRESULT WINAPI FileSaveRestoreOnINFA(HWND hWnd, LPCSTR pszTitle, LPCSTR pszINF,
854 LPCSTR pszSection, LPCSTR pszBackupDir,
855 LPCSTR pszBaseBackupFile, DWORD dwFlags)
857 UNICODE_STRING title, inf, section;
858 UNICODE_STRING backupdir, backupfile;
861 TRACE("(%p, %s, %s, %s, %s, %s, %ld)\n", hWnd, debugstr_a(pszTitle),
862 debugstr_a(pszINF), debugstr_a(pszSection), debugstr_a(pszBackupDir),
863 debugstr_a(pszBaseBackupFile), dwFlags);
865 RtlCreateUnicodeStringFromAsciiz(&title, pszTitle);
866 RtlCreateUnicodeStringFromAsciiz(&inf, pszINF);
867 RtlCreateUnicodeStringFromAsciiz(§ion, pszSection);
868 RtlCreateUnicodeStringFromAsciiz(&backupdir, pszBackupDir);
869 RtlCreateUnicodeStringFromAsciiz(&backupfile, pszBaseBackupFile);
871 hr = FileSaveRestoreOnINFW(hWnd, title.Buffer, inf.Buffer, section.Buffer,
872 backupdir.Buffer, backupfile.Buffer, dwFlags);
874 RtlFreeUnicodeString(&title);
875 RtlFreeUnicodeString(&inf);
876 RtlFreeUnicodeString(§ion);
877 RtlFreeUnicodeString(&backupdir);
878 RtlFreeUnicodeString(&backupfile);
883 /***********************************************************************
884 * FileSaveRestoreOnINFW (ADVPACK.@)
888 * hWnd [I] Handle to the window used for the display.
889 * pszTitle [I] Title of the window.
890 * pszINF [I] Fully-qualified INF filename.
891 * pszSection [I] GenInstall INF section name.
892 * pszBackupDir [I] Directory to store the backup file.
893 * pszBaseBackupFile [I] Basename of the backup files.
894 * dwFlags [I] See advpub.h
901 * If pszSection is NULL, the default section will be used.
906 HRESULT WINAPI FileSaveRestoreOnINFW(HWND hWnd, LPCWSTR pszTitle, LPCWSTR pszINF,
907 LPCWSTR pszSection, LPCWSTR pszBackupDir,
908 LPCWSTR pszBaseBackupFile, DWORD dwFlags)
910 FIXME("(%p, %s, %s, %s, %s, %s, %ld): stub\n", hWnd, debugstr_w(pszTitle),
911 debugstr_w(pszINF), debugstr_w(pszSection), debugstr_w(pszBackupDir),
912 debugstr_w(pszBaseBackupFile), dwFlags);
917 /***********************************************************************
918 * GetVersionFromFileA (ADVPACK.@)
920 * See GetVersionFromFileExW.
922 HRESULT WINAPI GetVersionFromFileA(LPCSTR Filename, LPDWORD MajorVer,
923 LPDWORD MinorVer, BOOL Version )
925 TRACE("(%s, %p, %p, %d)\n", debugstr_a(Filename), MajorVer, MinorVer, Version);
926 return GetVersionFromFileExA(Filename, MajorVer, MinorVer, Version);
929 /***********************************************************************
930 * GetVersionFromFileW (ADVPACK.@)
932 * See GetVersionFromFileExW.
934 HRESULT WINAPI GetVersionFromFileW(LPCWSTR Filename, LPDWORD MajorVer,
935 LPDWORD MinorVer, BOOL Version )
937 TRACE("(%s, %p, %p, %d)\n", debugstr_w(Filename), MajorVer, MinorVer, Version);
938 return GetVersionFromFileExW(Filename, MajorVer, MinorVer, Version);
941 /* data for GetVersionFromFileEx */
942 typedef struct tagLANGANDCODEPAGE
948 /***********************************************************************
949 * GetVersionFromFileExA (ADVPACK.@)
951 * See GetVersionFromFileExW.
953 HRESULT WINAPI GetVersionFromFileExA(LPCSTR lpszFilename, LPDWORD pdwMSVer,
954 LPDWORD pdwLSVer, BOOL bVersion )
956 UNICODE_STRING filename;
959 TRACE("(%s, %p, %p, %d)\n", debugstr_a(lpszFilename),
960 pdwMSVer, pdwLSVer, bVersion);
962 RtlCreateUnicodeStringFromAsciiz(&filename, lpszFilename);
964 res = GetVersionFromFileExW(filename.Buffer, pdwMSVer, pdwLSVer, bVersion);
966 RtlFreeUnicodeString(&filename);
971 /***********************************************************************
972 * GetVersionFromFileExW (ADVPACK.@)
974 * Gets the files version or language information.
977 * lpszFilename [I] The file to get the info from.
978 * pdwMSVer [O] Major version.
979 * pdwLSVer [O] Minor version.
980 * bVersion [I] Whether to retrieve version or language info.
983 * Always returns S_OK.
986 * If bVersion is TRUE, version information is retrieved, else
987 * pdwMSVer gets the language ID and pdwLSVer gets the codepage ID.
989 HRESULT WINAPI GetVersionFromFileExW(LPCWSTR lpszFilename, LPDWORD pdwMSVer,
990 LPDWORD pdwLSVer, BOOL bVersion )
992 VS_FIXEDFILEINFO *pFixedVersionInfo;
993 LANGANDCODEPAGE *pLangAndCodePage;
994 DWORD dwHandle, dwInfoSize;
995 WCHAR szWinDir[MAX_PATH];
996 WCHAR szFile[MAX_PATH];
997 LPVOID pVersionInfo = NULL;
998 BOOL bFileCopied = FALSE;
1001 static WCHAR backslash[] = {'\\',0};
1002 static WCHAR translation[] = {
1003 '\\','V','a','r','F','i','l','e','I','n','f','o',
1004 '\\','T','r','a','n','s','l','a','t','i','o','n',0
1007 TRACE("(%s, %p, %p, %d)\n", debugstr_w(lpszFilename),
1008 pdwMSVer, pdwLSVer, bVersion);
1013 lstrcpynW(szFile, lpszFilename, MAX_PATH);
1015 dwInfoSize = GetFileVersionInfoSizeW(szFile, &dwHandle);
1018 /* check that the file exists */
1019 if (GetFileAttributesW(szFile) == INVALID_FILE_ATTRIBUTES)
1022 /* file exists, but won't be found by GetFileVersionInfoSize,
1023 * so copy it to the temp dir where it will be found.
1025 GetWindowsDirectoryW(szWinDir, MAX_PATH);
1026 GetTempFileNameW(szWinDir, NULL, 0, szFile);
1027 CopyFileW(lpszFilename, szFile, FALSE);
1030 dwInfoSize = GetFileVersionInfoSizeW(szFile, &dwHandle);
1035 pVersionInfo = HeapAlloc(GetProcessHeap(), 0, dwInfoSize);
1039 if (!GetFileVersionInfoW(szFile, dwHandle, dwInfoSize, pVersionInfo))
1044 if (!VerQueryValueW(pVersionInfo, backslash,
1045 (LPVOID *)&pFixedVersionInfo, &uValueLen))
1051 *pdwMSVer = pFixedVersionInfo->dwFileVersionMS;
1052 *pdwLSVer = pFixedVersionInfo->dwFileVersionLS;
1056 if (!VerQueryValueW(pVersionInfo, translation,
1057 (LPVOID *)&pLangAndCodePage, &uValueLen))
1063 *pdwMSVer = pLangAndCodePage->wLanguage;
1064 *pdwLSVer = pLangAndCodePage->wCodePage;
1068 HeapFree(GetProcessHeap(), 0, pVersionInfo);
1071 DeleteFileW(szFile);