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;
66 TRACE("(%s, %s, %s, %d)\n", debugstr_a(lpcszFileList),
67 debugstr_a(lpcszBackupDir), debugstr_a(lpcszBaseName), dwFlags);
70 filelist = ansi_to_unicode_list(lpcszFileList);
74 RtlCreateUnicodeStringFromAsciiz(&backupdir, lpcszBackupDir);
75 RtlCreateUnicodeStringFromAsciiz(&basename, lpcszBaseName);
78 backup = backupdir.Buffer;
82 res = AddDelBackupEntryW(filelist, backup, basename.Buffer, dwFlags);
84 HeapFree(GetProcessHeap(), 0, filelist);
86 RtlFreeUnicodeString(&backupdir);
87 RtlFreeUnicodeString(&basename);
92 /***********************************************************************
93 * AddDelBackupEntryW (ADVPACK.@)
95 * Either appends the files in the file list to the backup section of
96 * the specified INI, or deletes the entries from the INI file.
99 * lpcszFileList [I] NULL-separated list of filenames.
100 * lpcszBackupDir [I] Path of the backup directory.
101 * lpcszBaseName [I] Basename of the INI file.
102 * dwFlags [I] AADBE_ADD_ENTRY adds the entries in the file list
103 * to the INI file, while AADBE_DEL_ENTRY removes
104 * the entries from the INI file.
110 * If the INI file does not exist before adding entries to it, the file
113 * If lpcszBackupDir is NULL, the INI file is assumed to exist in
114 * c:\windows or created there if it does not exist.
116 HRESULT WINAPI AddDelBackupEntryW(LPCWSTR lpcszFileList, LPCWSTR lpcszBackupDir,
117 LPCWSTR lpcszBaseName, DWORD dwFlags)
119 WCHAR szIniPath[MAX_PATH];
120 LPCWSTR szString = NULL;
122 static const WCHAR szBackupEntry[] = {
123 '-','1',',','0',',','0',',','0',',','0',',','0',',','-','1',0
126 static const WCHAR backslash[] = {'\\',0};
127 static const WCHAR ini[] = {'.','i','n','i',0};
128 static const WCHAR backup[] = {'b','a','c','k','u','p',0};
130 TRACE("(%s, %s, %s, %d)\n", debugstr_w(lpcszFileList),
131 debugstr_w(lpcszBackupDir), debugstr_w(lpcszBaseName), dwFlags);
133 if (!lpcszFileList || !*lpcszFileList)
137 lstrcpyW(szIniPath, lpcszBackupDir);
139 GetWindowsDirectoryW(szIniPath, MAX_PATH);
141 lstrcatW(szIniPath, backslash);
142 lstrcatW(szIniPath, lpcszBaseName);
143 lstrcatW(szIniPath, ini);
145 SetFileAttributesW(szIniPath, FILE_ATTRIBUTE_NORMAL);
147 if (dwFlags & AADBE_ADD_ENTRY)
148 szString = szBackupEntry;
149 else if (dwFlags & AADBE_DEL_ENTRY)
152 /* add or delete the INI entries */
153 while (*lpcszFileList)
155 WritePrivateProfileStringW(backup, lpcszFileList, szString, szIniPath);
156 lpcszFileList += lstrlenW(lpcszFileList) + 1;
159 /* hide the INI file */
160 SetFileAttributesW(szIniPath, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN);
165 /* FIXME: this is only for the local case, X:\ */
166 #define ROOT_LENGTH 3
168 static UINT CALLBACK pQuietQueueCallback(PVOID Context, UINT Notification,
169 UINT_PTR Param1, UINT_PTR Param2)
174 static UINT CALLBACK pQueueCallback(PVOID Context, UINT Notification,
175 UINT_PTR Param1, UINT_PTR Param2)
177 /* only be verbose for error notifications */
179 Notification == SPFILENOTIFY_RENAMEERROR ||
180 Notification == SPFILENOTIFY_DELETEERROR ||
181 Notification == SPFILENOTIFY_COPYERROR)
183 return SetupDefaultQueueCallbackW(Context, Notification,
190 /***********************************************************************
191 * AdvInstallFileA (ADVPACK.@)
193 * See AdvInstallFileW.
195 HRESULT WINAPI AdvInstallFileA(HWND hwnd, LPCSTR lpszSourceDir, LPCSTR lpszSourceFile,
196 LPCSTR lpszDestDir, LPCSTR lpszDestFile,
197 DWORD dwFlags, DWORD dwReserved)
199 UNICODE_STRING sourcedir, sourcefile;
200 UNICODE_STRING destdir, destfile;
203 TRACE("(%p, %s, %s, %s, %s, %d, %d)\n", hwnd, debugstr_a(lpszSourceDir),
204 debugstr_a(lpszSourceFile), debugstr_a(lpszDestDir),
205 debugstr_a(lpszDestFile), dwFlags, dwReserved);
207 if (!lpszSourceDir || !lpszSourceFile || !lpszDestDir)
210 RtlCreateUnicodeStringFromAsciiz(&sourcedir, lpszSourceDir);
211 RtlCreateUnicodeStringFromAsciiz(&sourcefile, lpszSourceFile);
212 RtlCreateUnicodeStringFromAsciiz(&destdir, lpszDestDir);
213 RtlCreateUnicodeStringFromAsciiz(&destfile, lpszDestFile);
215 res = AdvInstallFileW(hwnd, sourcedir.Buffer, sourcefile.Buffer,
216 destdir.Buffer, destfile.Buffer, dwFlags, dwReserved);
218 RtlFreeUnicodeString(&sourcedir);
219 RtlFreeUnicodeString(&sourcefile);
220 RtlFreeUnicodeString(&destdir);
221 RtlFreeUnicodeString(&destfile);
226 /***********************************************************************
227 * AdvInstallFileW (ADVPACK.@)
229 * Copies a file from the source to a destination.
232 * hwnd [I] Handle to the window used for messages.
233 * lpszSourceDir [I] Source directory.
234 * lpszSourceFile [I] Source filename.
235 * lpszDestDir [I] Destination directory.
236 * lpszDestFile [I] Optional destination filename.
237 * dwFlags [I] See advpub.h.
238 * dwReserved [I] Reserved. Must be 0.
245 * If lpszDestFile is NULL, the destination filename is the same as
248 HRESULT WINAPI AdvInstallFileW(HWND hwnd, LPCWSTR lpszSourceDir, LPCWSTR lpszSourceFile,
249 LPCWSTR lpszDestDir, LPCWSTR lpszDestFile,
250 DWORD dwFlags, DWORD dwReserved)
252 PSP_FILE_CALLBACK_W pFileCallback;
253 LPWSTR szDestFilename;
255 WCHAR szRootPath[ROOT_LENGTH];
256 DWORD dwLen, dwLastError;
260 TRACE("(%p, %s, %s, %s, %s, %d, %d)\n", hwnd, debugstr_w(lpszSourceDir),
261 debugstr_w(lpszSourceFile), debugstr_w(lpszDestDir),
262 debugstr_w(lpszDestFile), dwFlags, dwReserved);
264 if (!lpszSourceDir || !lpszSourceFile || !lpszDestDir)
267 fileQueue = SetupOpenFileQueue();
268 if (fileQueue == INVALID_HANDLE_VALUE)
269 return HRESULT_FROM_WIN32(GetLastError());
272 dwLastError = ERROR_SUCCESS;
274 lstrcpynW(szRootPath, lpszSourceDir, ROOT_LENGTH);
275 szPath = lpszSourceDir + ROOT_LENGTH;
277 /* use lpszSourceFile as destination filename if lpszDestFile is NULL */
280 dwLen = lstrlenW(lpszDestFile);
281 szDestFilename = HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(WCHAR));
282 lstrcpyW(szDestFilename, lpszDestFile);
286 dwLen = lstrlenW(lpszSourceFile);
287 szDestFilename = HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(WCHAR));
288 lstrcpyW(szDestFilename, lpszSourceFile);
291 /* add the file copy operation to the setup queue */
292 if (!SetupQueueCopyW(fileQueue, szRootPath, szPath, lpszSourceFile, NULL,
293 NULL, lpszDestDir, szDestFilename, dwFlags))
295 dwLastError = GetLastError();
299 pContext = SetupInitDefaultQueueCallbackEx(hwnd, INVALID_HANDLE_VALUE,
303 dwLastError = GetLastError();
307 /* don't output anything for AIF_QUIET */
308 if (dwFlags & AIF_QUIET)
309 pFileCallback = pQuietQueueCallback;
311 pFileCallback = pQueueCallback;
313 /* perform the file copy */
314 if (!SetupCommitFileQueueW(hwnd, fileQueue, pFileCallback, pContext))
316 dwLastError = GetLastError();
321 SetupTermDefaultQueueCallback(pContext);
322 SetupCloseFileQueue(fileQueue);
324 HeapFree(GetProcessHeap(), 0, szDestFilename);
326 return HRESULT_FROM_WIN32(dwLastError);
329 static HRESULT DELNODE_recurse_dirtree(LPWSTR fname, DWORD flags)
331 DWORD fattrs = GetFileAttributesW(fname);
332 HRESULT ret = E_FAIL;
334 static const WCHAR backslash[] = {'\\',0};
335 static const WCHAR asterisk[] = {'*',0};
336 static const WCHAR dot[] = {'.',0};
337 static const WCHAR dotdot[] = {'.','.',0};
339 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
342 WIN32_FIND_DATAW w32fd;
344 int fname_len = lstrlenW(fname);
346 /* Generate a path with wildcard suitable for iterating */
347 if (lstrcmpW(CharPrevW(fname, fname + fname_len), backslash))
349 lstrcpyW(fname + fname_len, backslash);
352 lstrcpyW(fname + fname_len, asterisk);
354 if ((hFindFile = FindFirstFileW(fname, &w32fd)) != INVALID_HANDLE_VALUE)
356 /* Iterate through the files in the directory */
357 for (done = FALSE; !done; done = !FindNextFileW(hFindFile, &w32fd))
359 TRACE("%s\n", debugstr_w(w32fd.cFileName));
360 if (lstrcmpW(dot, w32fd.cFileName) != 0 &&
361 lstrcmpW(dotdot, w32fd.cFileName) != 0)
363 lstrcpyW(fname + fname_len, w32fd.cFileName);
364 if (DELNODE_recurse_dirtree(fname, flags) != S_OK)
370 FindClose(hFindFile);
373 /* We're done with this directory, so restore the old path without wildcard */
374 *(fname + fname_len) = '\0';
378 TRACE("%s: directory\n", debugstr_w(fname));
379 if (SetFileAttributesW(fname, FILE_ATTRIBUTE_NORMAL) && RemoveDirectoryW(fname))
387 TRACE("%s: file\n", debugstr_w(fname));
388 if (SetFileAttributesW(fname, FILE_ATTRIBUTE_NORMAL) && DeleteFileW(fname))
397 /***********************************************************************
398 * DelNodeA (ADVPACK.@)
402 HRESULT WINAPI DelNodeA(LPCSTR pszFileOrDirName, DWORD dwFlags)
404 UNICODE_STRING fileordirname;
407 TRACE("(%s, %d)\n", debugstr_a(pszFileOrDirName), dwFlags);
409 RtlCreateUnicodeStringFromAsciiz(&fileordirname, pszFileOrDirName);
411 res = DelNodeW(fileordirname.Buffer, dwFlags);
413 RtlFreeUnicodeString(&fileordirname);
418 /***********************************************************************
419 * DelNodeW (ADVPACK.@)
421 * Deletes a file or directory
424 * pszFileOrDirName [I] Name of file or directory to delete
425 * dwFlags [I] Flags; see include/advpub.h
433 * - Native version apparently does a lot of checking to make sure
434 * we're not trying to delete a system directory etc.
436 HRESULT WINAPI DelNodeW(LPCWSTR pszFileOrDirName, DWORD dwFlags)
438 WCHAR fname[MAX_PATH];
439 HRESULT ret = E_FAIL;
441 TRACE("(%s, %d)\n", debugstr_w(pszFileOrDirName), dwFlags);
444 FIXME("Flags ignored!\n");
446 if (pszFileOrDirName && *pszFileOrDirName)
448 lstrcpyW(fname, pszFileOrDirName);
450 /* TODO: Should check for system directory deletion etc. here */
452 ret = DELNODE_recurse_dirtree(fname, dwFlags);
458 /***********************************************************************
459 * DelNodeRunDLL32A (ADVPACK.@)
461 * See DelNodeRunDLL32W.
463 HRESULT WINAPI DelNodeRunDLL32A(HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show)
465 UNICODE_STRING params;
468 TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_a(cmdline), show);
470 RtlCreateUnicodeStringFromAsciiz(¶ms, cmdline);
472 hr = DelNodeRunDLL32W(hWnd, hInst, params.Buffer, show);
474 RtlFreeUnicodeString(¶ms);
479 /***********************************************************************
480 * DelNodeRunDLL32W (ADVPACK.@)
482 * Deletes a file or directory, WinMain style.
485 * hWnd [I] Handle to the window used for the display.
486 * hInst [I] Instance of the process.
487 * cmdline [I] Contains parameters in the order FileOrDirName,Flags.
488 * show [I] How the window should be shown.
494 HRESULT WINAPI DelNodeRunDLL32W(HWND hWnd, HINSTANCE hInst, LPWSTR cmdline, INT show)
496 LPWSTR szFilename, szFlags;
497 LPWSTR cmdline_copy, cmdline_ptr;
501 TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_w(cmdline), show);
503 cmdline_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(cmdline) + 1) * sizeof(WCHAR));
504 cmdline_ptr = cmdline_copy;
505 lstrcpyW(cmdline_copy, cmdline);
507 /* get the parameters at indexes 0 and 1 respectively */
508 szFilename = get_parameter(&cmdline_ptr, ',');
509 szFlags = get_parameter(&cmdline_ptr, ',');
512 dwFlags = atolW(szFlags);
514 res = DelNodeW(szFilename, dwFlags);
516 HeapFree(GetProcessHeap(), 0, cmdline_copy);
521 /* The following defintions were copied from dlls/cabinet/cabinet.h */
523 /* EXTRACTdest flags */
524 #define EXTRACT_FILLFILELIST 0x00000001
525 #define EXTRACT_EXTRACTFILES 0x00000002
527 struct ExtractFileList {
529 struct ExtractFileList *next;
530 BOOL unknown; /* always 1L */
533 /* the first parameter of the function Extract */
535 long result1; /* 0x000 */
536 long unknown1[3]; /* 0x004 */
537 struct ExtractFileList *filelist; /* 0x010 */
538 long filecount; /* 0x014 */
539 DWORD flags; /* 0x018 */
540 char directory[0x104]; /* 0x01c */
541 char lastfile[0x20c]; /* 0x120 */
544 static HRESULT (WINAPI *pExtract)(EXTRACTdest*, LPCSTR);
546 /* removes legal characters before and after file list, and
547 * converts the file list to a NULL-separated list
549 static LPSTR convert_file_list(LPCSTR FileList, DWORD *dwNumFiles)
552 const char *first = FileList;
553 const char *last = FileList + strlen(FileList) - 1;
554 LPSTR szConvertedList, temp;
556 /* any number of these chars before the list is OK */
557 while (first < last && (*first == ' ' || *first == '\t' || *first == ':'))
560 /* any number of these chars after the list is OK */
561 while (last > first && (*last == ' ' || *last == '\t' || *last == ':'))
567 dwLen = last - first + 3; /* room for double-null termination */
568 szConvertedList = HeapAlloc(GetProcessHeap(), 0, dwLen);
569 lstrcpynA(szConvertedList, first, dwLen - 1);
571 szConvertedList[dwLen - 1] = '\0';
572 szConvertedList[dwLen] = '\0';
575 if (!lstrlenA(szConvertedList))
577 HeapFree(GetProcessHeap(), 0, szConvertedList);
583 /* convert the colons to double-null termination */
584 temp = szConvertedList;
596 return szConvertedList;
599 static void free_file_node(struct ExtractFileList *pNode)
601 HeapFree(GetProcessHeap(), 0, pNode->filename);
602 HeapFree(GetProcessHeap(), 0, pNode);
605 /* determines whether szFile is in the NULL-separated szFileList */
606 static BOOL file_in_list(LPCSTR szFile, LPCSTR szFileList)
608 DWORD dwLen = lstrlenA(szFile);
613 dwTestLen = lstrlenA(szFileList);
615 if (dwTestLen == dwLen)
617 if (!lstrcmpiA(szFile, szFileList))
621 szFileList += dwTestLen + 1;
627 /* removes nodes from the linked list that aren't specified in szFileList
628 * returns the number of files that are in both the linked list and szFileList
630 static DWORD fill_file_list(EXTRACTdest *extractDest, LPCSTR szCabName, LPCSTR szFileList)
632 DWORD dwNumFound = 0;
633 struct ExtractFileList *pNode;
634 struct ExtractFileList *prev = NULL;
636 extractDest->flags |= EXTRACT_FILLFILELIST;
637 if (pExtract(extractDest, szCabName))
639 extractDest->flags &= ~EXTRACT_FILLFILELIST;
643 pNode = extractDest->filelist;
646 if (file_in_list(pNode->filename, szFileList))
654 prev->next = pNode->next;
655 free_file_node(pNode);
660 extractDest->filelist = pNode->next;
661 free_file_node(pNode);
662 pNode = extractDest->filelist;
666 extractDest->flags &= ~EXTRACT_FILLFILELIST;
670 /***********************************************************************
671 * ExtractFilesA (ADVPACK.@)
673 * Extracts the specified files from a cab archive into
674 * a destination directory.
677 * CabName [I] Filename of the cab archive.
678 * ExpandDir [I] Destination directory for the extracted files.
679 * Flags [I] Reserved.
680 * FileList [I] Optional list of files to extract. See NOTES.
681 * LReserved [I] Reserved. Must be NULL.
682 * Reserved [I] Reserved. Must be 0.
689 * FileList is a colon-separated list of filenames. If FileList is
690 * non-NULL, only the files in the list will be extracted from the
691 * cab file, otherwise all files will be extracted. Any number of
692 * spaces, tabs, or colons can be before or after the list, but
693 * the list itself must only be separated by colons.
695 HRESULT WINAPI ExtractFilesA(LPCSTR CabName, LPCSTR ExpandDir, DWORD Flags,
696 LPCSTR FileList, LPVOID LReserved, DWORD Reserved)
698 EXTRACTdest extractDest;
701 DWORD dwFileCount = 0;
702 DWORD dwFilesFound = 0;
703 LPSTR szConvertedList = NULL;
705 TRACE("(%s, %s, %d, %s, %p, %d)\n", debugstr_a(CabName), debugstr_a(ExpandDir),
706 Flags, debugstr_a(FileList), LReserved, Reserved);
708 if (!CabName || !ExpandDir)
711 if (GetFileAttributesA(ExpandDir) == INVALID_FILE_ATTRIBUTES)
712 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
714 hCabinet = LoadLibraryA("cabinet.dll");
718 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
725 ZeroMemory(&extractDest, sizeof(EXTRACTdest));
726 lstrcpyA(extractDest.directory, ExpandDir);
730 szConvertedList = convert_file_list(FileList, &dwFileCount);
731 if (!szConvertedList || dwFileCount == -1)
737 dwFilesFound = fill_file_list(&extractDest, CabName, szConvertedList);
738 if (dwFilesFound != dwFileCount)
745 extractDest.flags |= EXTRACT_FILLFILELIST;
747 extractDest.flags |= EXTRACT_EXTRACTFILES;
748 res = pExtract(&extractDest, CabName);
750 if (extractDest.filelist)
752 struct ExtractFileList* curr = extractDest.filelist;
753 struct ExtractFileList* next;
758 free_file_node(curr);
764 FreeLibrary(hCabinet);
765 HeapFree(GetProcessHeap(), 0, szConvertedList);
770 /***********************************************************************
771 * FileSaveMarkNotExistA (ADVPACK.@)
773 * See FileSaveMarkNotExistW.
775 HRESULT WINAPI FileSaveMarkNotExistA(LPSTR pszFileList, LPSTR pszDir, LPSTR pszBaseName)
777 TRACE("(%s, %s, %s)\n", debugstr_a(pszFileList),
778 debugstr_a(pszDir), debugstr_a(pszBaseName));
780 return AddDelBackupEntryA(pszFileList, pszDir, pszBaseName, AADBE_DEL_ENTRY);
783 /***********************************************************************
784 * FileSaveMarkNotExistW (ADVPACK.@)
786 * Marks the files in the file list as not existing so they won't be
787 * backed up during a save.
790 * pszFileList [I] NULL-separated list of filenames.
791 * pszDir [I] Path of the backup directory.
792 * pszBaseName [I] Basename of the INI file.
798 HRESULT WINAPI FileSaveMarkNotExistW(LPWSTR pszFileList, LPWSTR pszDir, LPWSTR pszBaseName)
800 TRACE("(%s, %s, %s)\n", debugstr_w(pszFileList),
801 debugstr_w(pszDir), debugstr_w(pszBaseName));
803 return AddDelBackupEntryW(pszFileList, pszDir, pszBaseName, AADBE_DEL_ENTRY);
806 /***********************************************************************
807 * FileSaveRestoreA (ADVPACK.@)
809 * See FileSaveRestoreW.
811 HRESULT WINAPI FileSaveRestoreA(HWND hDlg, LPSTR pszFileList, LPSTR pszDir,
812 LPSTR pszBaseName, DWORD dwFlags)
814 UNICODE_STRING filelist, dir, basename;
817 TRACE("(%p, %s, %s, %s, %d)\n", hDlg, debugstr_a(pszFileList),
818 debugstr_a(pszDir), debugstr_a(pszBaseName), dwFlags);
820 RtlCreateUnicodeStringFromAsciiz(&filelist, pszFileList);
821 RtlCreateUnicodeStringFromAsciiz(&dir, pszDir);
822 RtlCreateUnicodeStringFromAsciiz(&basename, pszBaseName);
824 hr = FileSaveRestoreW(hDlg, filelist.Buffer, dir.Buffer,
825 basename.Buffer, dwFlags);
827 RtlFreeUnicodeString(&filelist);
828 RtlFreeUnicodeString(&dir);
829 RtlFreeUnicodeString(&basename);
834 /***********************************************************************
835 * FileSaveRestoreW (ADVPACK.@)
837 * Saves or restores the files in the specified file list.
840 * hDlg [I] Handle to the dialog used for the display.
841 * pszFileList [I] NULL-separated list of filenames.
842 * pszDir [I] Path of the backup directory.
843 * pszBaseName [I] Basename of the backup files.
844 * dwFlags [I] See advpub.h.
851 * If pszFileList is NULL on restore, all files will be restored.
856 HRESULT WINAPI FileSaveRestoreW(HWND hDlg, LPWSTR pszFileList, LPWSTR pszDir,
857 LPWSTR pszBaseName, DWORD dwFlags)
859 FIXME("(%p, %s, %s, %s, %d) stub\n", hDlg, debugstr_w(pszFileList),
860 debugstr_w(pszDir), debugstr_w(pszBaseName), dwFlags);
865 /***********************************************************************
866 * FileSaveRestoreOnINFA (ADVPACK.@)
868 * See FileSaveRestoreOnINFW.
870 HRESULT WINAPI FileSaveRestoreOnINFA(HWND hWnd, LPCSTR pszTitle, LPCSTR pszINF,
871 LPCSTR pszSection, LPCSTR pszBackupDir,
872 LPCSTR pszBaseBackupFile, DWORD dwFlags)
874 UNICODE_STRING title, inf, section;
875 UNICODE_STRING backupdir, backupfile;
878 TRACE("(%p, %s, %s, %s, %s, %s, %d)\n", hWnd, debugstr_a(pszTitle),
879 debugstr_a(pszINF), debugstr_a(pszSection), debugstr_a(pszBackupDir),
880 debugstr_a(pszBaseBackupFile), dwFlags);
882 RtlCreateUnicodeStringFromAsciiz(&title, pszTitle);
883 RtlCreateUnicodeStringFromAsciiz(&inf, pszINF);
884 RtlCreateUnicodeStringFromAsciiz(§ion, pszSection);
885 RtlCreateUnicodeStringFromAsciiz(&backupdir, pszBackupDir);
886 RtlCreateUnicodeStringFromAsciiz(&backupfile, pszBaseBackupFile);
888 hr = FileSaveRestoreOnINFW(hWnd, title.Buffer, inf.Buffer, section.Buffer,
889 backupdir.Buffer, backupfile.Buffer, dwFlags);
891 RtlFreeUnicodeString(&title);
892 RtlFreeUnicodeString(&inf);
893 RtlFreeUnicodeString(§ion);
894 RtlFreeUnicodeString(&backupdir);
895 RtlFreeUnicodeString(&backupfile);
900 /***********************************************************************
901 * FileSaveRestoreOnINFW (ADVPACK.@)
905 * hWnd [I] Handle to the window used for the display.
906 * pszTitle [I] Title of the window.
907 * pszINF [I] Fully-qualified INF filename.
908 * pszSection [I] GenInstall INF section name.
909 * pszBackupDir [I] Directory to store the backup file.
910 * pszBaseBackupFile [I] Basename of the backup files.
911 * dwFlags [I] See advpub.h
918 * If pszSection is NULL, the default section will be used.
923 HRESULT WINAPI FileSaveRestoreOnINFW(HWND hWnd, LPCWSTR pszTitle, LPCWSTR pszINF,
924 LPCWSTR pszSection, LPCWSTR pszBackupDir,
925 LPCWSTR pszBaseBackupFile, DWORD dwFlags)
927 FIXME("(%p, %s, %s, %s, %s, %s, %d): stub\n", hWnd, debugstr_w(pszTitle),
928 debugstr_w(pszINF), debugstr_w(pszSection), debugstr_w(pszBackupDir),
929 debugstr_w(pszBaseBackupFile), dwFlags);
934 /***********************************************************************
935 * GetVersionFromFileA (ADVPACK.@)
937 * See GetVersionFromFileExW.
939 HRESULT WINAPI GetVersionFromFileA(LPCSTR Filename, LPDWORD MajorVer,
940 LPDWORD MinorVer, BOOL Version )
942 TRACE("(%s, %p, %p, %d)\n", debugstr_a(Filename), MajorVer, MinorVer, Version);
943 return GetVersionFromFileExA(Filename, MajorVer, MinorVer, Version);
946 /***********************************************************************
947 * GetVersionFromFileW (ADVPACK.@)
949 * See GetVersionFromFileExW.
951 HRESULT WINAPI GetVersionFromFileW(LPCWSTR Filename, LPDWORD MajorVer,
952 LPDWORD MinorVer, BOOL Version )
954 TRACE("(%s, %p, %p, %d)\n", debugstr_w(Filename), MajorVer, MinorVer, Version);
955 return GetVersionFromFileExW(Filename, MajorVer, MinorVer, Version);
958 /* data for GetVersionFromFileEx */
959 typedef struct tagLANGANDCODEPAGE
965 /***********************************************************************
966 * GetVersionFromFileExA (ADVPACK.@)
968 * See GetVersionFromFileExW.
970 HRESULT WINAPI GetVersionFromFileExA(LPCSTR lpszFilename, LPDWORD pdwMSVer,
971 LPDWORD pdwLSVer, BOOL bVersion )
973 UNICODE_STRING filename;
976 TRACE("(%s, %p, %p, %d)\n", debugstr_a(lpszFilename),
977 pdwMSVer, pdwLSVer, bVersion);
979 RtlCreateUnicodeStringFromAsciiz(&filename, lpszFilename);
981 res = GetVersionFromFileExW(filename.Buffer, pdwMSVer, pdwLSVer, bVersion);
983 RtlFreeUnicodeString(&filename);
988 /***********************************************************************
989 * GetVersionFromFileExW (ADVPACK.@)
991 * Gets the files version or language information.
994 * lpszFilename [I] The file to get the info from.
995 * pdwMSVer [O] Major version.
996 * pdwLSVer [O] Minor version.
997 * bVersion [I] Whether to retrieve version or language info.
1000 * Always returns S_OK.
1003 * If bVersion is TRUE, version information is retrieved, else
1004 * pdwMSVer gets the language ID and pdwLSVer gets the codepage ID.
1006 HRESULT WINAPI GetVersionFromFileExW(LPCWSTR lpszFilename, LPDWORD pdwMSVer,
1007 LPDWORD pdwLSVer, BOOL bVersion )
1009 VS_FIXEDFILEINFO *pFixedVersionInfo;
1010 LANGANDCODEPAGE *pLangAndCodePage;
1011 DWORD dwHandle, dwInfoSize;
1012 WCHAR szWinDir[MAX_PATH];
1013 WCHAR szFile[MAX_PATH];
1014 LPVOID pVersionInfo = NULL;
1015 BOOL bFileCopied = FALSE;
1018 static WCHAR backslash[] = {'\\',0};
1019 static WCHAR translation[] = {
1020 '\\','V','a','r','F','i','l','e','I','n','f','o',
1021 '\\','T','r','a','n','s','l','a','t','i','o','n',0
1024 TRACE("(%s, %p, %p, %d)\n", debugstr_w(lpszFilename),
1025 pdwMSVer, pdwLSVer, bVersion);
1030 lstrcpynW(szFile, lpszFilename, MAX_PATH);
1032 dwInfoSize = GetFileVersionInfoSizeW(szFile, &dwHandle);
1035 /* check that the file exists */
1036 if (GetFileAttributesW(szFile) == INVALID_FILE_ATTRIBUTES)
1039 /* file exists, but won't be found by GetFileVersionInfoSize,
1040 * so copy it to the temp dir where it will be found.
1042 GetWindowsDirectoryW(szWinDir, MAX_PATH);
1043 GetTempFileNameW(szWinDir, NULL, 0, szFile);
1044 CopyFileW(lpszFilename, szFile, FALSE);
1047 dwInfoSize = GetFileVersionInfoSizeW(szFile, &dwHandle);
1052 pVersionInfo = HeapAlloc(GetProcessHeap(), 0, dwInfoSize);
1056 if (!GetFileVersionInfoW(szFile, dwHandle, dwInfoSize, pVersionInfo))
1061 if (!VerQueryValueW(pVersionInfo, backslash,
1062 (LPVOID *)&pFixedVersionInfo, &uValueLen))
1068 *pdwMSVer = pFixedVersionInfo->dwFileVersionMS;
1069 *pdwLSVer = pFixedVersionInfo->dwFileVersionLS;
1073 if (!VerQueryValueW(pVersionInfo, translation,
1074 (LPVOID *)&pLangAndCodePage, &uValueLen))
1080 *pdwMSVer = pLangAndCodePage->wLanguage;
1081 *pdwLSVer = pLangAndCodePage->wCodePage;
1085 HeapFree(GetProcessHeap(), 0, pVersionInfo);
1088 DeleteFileW(szFile);