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 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 (fname_len && fname[fname_len-1] != '\\') fname[fname_len++] = '\\';
347 lstrcpyW(fname + fname_len, asterisk);
349 if ((hFindFile = FindFirstFileW(fname, &w32fd)) != INVALID_HANDLE_VALUE)
351 /* Iterate through the files in the directory */
352 for (done = FALSE; !done; done = !FindNextFileW(hFindFile, &w32fd))
354 TRACE("%s\n", debugstr_w(w32fd.cFileName));
355 if (lstrcmpW(dot, w32fd.cFileName) != 0 &&
356 lstrcmpW(dotdot, w32fd.cFileName) != 0)
358 lstrcpyW(fname + fname_len, w32fd.cFileName);
359 if (DELNODE_recurse_dirtree(fname, flags) != S_OK)
365 FindClose(hFindFile);
368 /* We're done with this directory, so restore the old path without wildcard */
369 *(fname + fname_len) = '\0';
373 TRACE("%s: directory\n", debugstr_w(fname));
374 if (SetFileAttributesW(fname, FILE_ATTRIBUTE_NORMAL) && RemoveDirectoryW(fname))
382 TRACE("%s: file\n", debugstr_w(fname));
383 if (SetFileAttributesW(fname, FILE_ATTRIBUTE_NORMAL) && DeleteFileW(fname))
392 /***********************************************************************
393 * DelNodeA (ADVPACK.@)
397 HRESULT WINAPI DelNodeA(LPCSTR pszFileOrDirName, DWORD dwFlags)
399 UNICODE_STRING fileordirname;
402 TRACE("(%s, %d)\n", debugstr_a(pszFileOrDirName), dwFlags);
404 RtlCreateUnicodeStringFromAsciiz(&fileordirname, pszFileOrDirName);
406 res = DelNodeW(fileordirname.Buffer, dwFlags);
408 RtlFreeUnicodeString(&fileordirname);
413 /***********************************************************************
414 * DelNodeW (ADVPACK.@)
416 * Deletes a file or directory
419 * pszFileOrDirName [I] Name of file or directory to delete
420 * dwFlags [I] Flags; see include/advpub.h
428 * - Native version apparently does a lot of checking to make sure
429 * we're not trying to delete a system directory etc.
431 HRESULT WINAPI DelNodeW(LPCWSTR pszFileOrDirName, DWORD dwFlags)
433 WCHAR fname[MAX_PATH];
434 HRESULT ret = E_FAIL;
436 TRACE("(%s, %d)\n", debugstr_w(pszFileOrDirName), dwFlags);
439 FIXME("Flags ignored!\n");
441 if (pszFileOrDirName && *pszFileOrDirName)
443 lstrcpyW(fname, pszFileOrDirName);
445 /* TODO: Should check for system directory deletion etc. here */
447 ret = DELNODE_recurse_dirtree(fname, dwFlags);
453 /***********************************************************************
454 * DelNodeRunDLL32A (ADVPACK.@)
456 * See DelNodeRunDLL32W.
458 HRESULT WINAPI DelNodeRunDLL32A(HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show)
460 UNICODE_STRING params;
463 TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_a(cmdline), show);
465 RtlCreateUnicodeStringFromAsciiz(¶ms, cmdline);
467 hr = DelNodeRunDLL32W(hWnd, hInst, params.Buffer, show);
469 RtlFreeUnicodeString(¶ms);
474 /***********************************************************************
475 * DelNodeRunDLL32W (ADVPACK.@)
477 * Deletes a file or directory, WinMain style.
480 * hWnd [I] Handle to the window used for the display.
481 * hInst [I] Instance of the process.
482 * cmdline [I] Contains parameters in the order FileOrDirName,Flags.
483 * show [I] How the window should be shown.
489 HRESULT WINAPI DelNodeRunDLL32W(HWND hWnd, HINSTANCE hInst, LPWSTR cmdline, INT show)
491 LPWSTR szFilename, szFlags;
492 LPWSTR cmdline_copy, cmdline_ptr;
496 TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_w(cmdline), show);
498 cmdline_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(cmdline) + 1) * sizeof(WCHAR));
499 cmdline_ptr = cmdline_copy;
500 lstrcpyW(cmdline_copy, cmdline);
502 /* get the parameters at indexes 0 and 1 respectively */
503 szFilename = get_parameter(&cmdline_ptr, ',');
504 szFlags = get_parameter(&cmdline_ptr, ',');
507 dwFlags = atolW(szFlags);
509 res = DelNodeW(szFilename, dwFlags);
511 HeapFree(GetProcessHeap(), 0, cmdline_copy);
516 /* The following defintions were copied from dlls/cabinet/cabinet.h */
518 /* EXTRACTdest flags */
519 #define EXTRACT_FILLFILELIST 0x00000001
520 #define EXTRACT_EXTRACTFILES 0x00000002
522 struct ExtractFileList {
524 struct ExtractFileList *next;
525 BOOL unknown; /* always 1L */
528 /* the first parameter of the function Extract */
530 long result1; /* 0x000 */
531 long unknown1[3]; /* 0x004 */
532 struct ExtractFileList *filelist; /* 0x010 */
533 long filecount; /* 0x014 */
534 DWORD flags; /* 0x018 */
535 char directory[0x104]; /* 0x01c */
536 char lastfile[0x20c]; /* 0x120 */
539 static HRESULT (WINAPI *pExtract)(EXTRACTdest*, LPCSTR);
541 /* removes legal characters before and after file list, and
542 * converts the file list to a NULL-separated list
544 static LPSTR convert_file_list(LPCSTR FileList, DWORD *dwNumFiles)
547 const char *first = FileList;
548 const char *last = FileList + strlen(FileList) - 1;
549 LPSTR szConvertedList, temp;
551 /* any number of these chars before the list is OK */
552 while (first < last && (*first == ' ' || *first == '\t' || *first == ':'))
555 /* any number of these chars after the list is OK */
556 while (last > first && (*last == ' ' || *last == '\t' || *last == ':'))
562 dwLen = last - first + 3; /* room for double-null termination */
563 szConvertedList = HeapAlloc(GetProcessHeap(), 0, dwLen);
564 lstrcpynA(szConvertedList, first, dwLen - 1);
566 szConvertedList[dwLen - 1] = '\0';
567 szConvertedList[dwLen] = '\0';
570 if (!lstrlenA(szConvertedList))
572 HeapFree(GetProcessHeap(), 0, szConvertedList);
578 /* convert the colons to double-null termination */
579 temp = szConvertedList;
591 return szConvertedList;
594 static void free_file_node(struct ExtractFileList *pNode)
596 HeapFree(GetProcessHeap(), 0, pNode->filename);
597 HeapFree(GetProcessHeap(), 0, pNode);
600 /* determines whether szFile is in the NULL-separated szFileList */
601 static BOOL file_in_list(LPCSTR szFile, LPCSTR szFileList)
603 DWORD dwLen = lstrlenA(szFile);
608 dwTestLen = lstrlenA(szFileList);
610 if (dwTestLen == dwLen)
612 if (!lstrcmpiA(szFile, szFileList))
616 szFileList += dwTestLen + 1;
622 /* removes nodes from the linked list that aren't specified in szFileList
623 * returns the number of files that are in both the linked list and szFileList
625 static DWORD fill_file_list(EXTRACTdest *extractDest, LPCSTR szCabName, LPCSTR szFileList)
627 DWORD dwNumFound = 0;
628 struct ExtractFileList *pNode;
629 struct ExtractFileList *prev = NULL;
631 extractDest->flags |= EXTRACT_FILLFILELIST;
632 if (pExtract(extractDest, szCabName))
634 extractDest->flags &= ~EXTRACT_FILLFILELIST;
638 pNode = extractDest->filelist;
641 if (file_in_list(pNode->filename, szFileList))
649 prev->next = pNode->next;
650 free_file_node(pNode);
655 extractDest->filelist = pNode->next;
656 free_file_node(pNode);
657 pNode = extractDest->filelist;
661 extractDest->flags &= ~EXTRACT_FILLFILELIST;
665 /***********************************************************************
666 * ExtractFilesA (ADVPACK.@)
668 * Extracts the specified files from a cab archive into
669 * a destination directory.
672 * CabName [I] Filename of the cab archive.
673 * ExpandDir [I] Destination directory for the extracted files.
674 * Flags [I] Reserved.
675 * FileList [I] Optional list of files to extract. See NOTES.
676 * LReserved [I] Reserved. Must be NULL.
677 * Reserved [I] Reserved. Must be 0.
684 * FileList is a colon-separated list of filenames. If FileList is
685 * non-NULL, only the files in the list will be extracted from the
686 * cab file, otherwise all files will be extracted. Any number of
687 * spaces, tabs, or colons can be before or after the list, but
688 * the list itself must only be separated by colons.
690 HRESULT WINAPI ExtractFilesA(LPCSTR CabName, LPCSTR ExpandDir, DWORD Flags,
691 LPCSTR FileList, LPVOID LReserved, DWORD Reserved)
693 EXTRACTdest extractDest;
696 DWORD dwFileCount = 0;
697 DWORD dwFilesFound = 0;
698 LPSTR szConvertedList = NULL;
700 TRACE("(%s, %s, %d, %s, %p, %d)\n", debugstr_a(CabName), debugstr_a(ExpandDir),
701 Flags, debugstr_a(FileList), LReserved, Reserved);
703 if (!CabName || !ExpandDir)
706 if (GetFileAttributesA(ExpandDir) == INVALID_FILE_ATTRIBUTES)
707 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
709 hCabinet = LoadLibraryA("cabinet.dll");
713 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
720 ZeroMemory(&extractDest, sizeof(EXTRACTdest));
721 lstrcpyA(extractDest.directory, ExpandDir);
725 szConvertedList = convert_file_list(FileList, &dwFileCount);
726 if (!szConvertedList || dwFileCount == -1)
732 dwFilesFound = fill_file_list(&extractDest, CabName, szConvertedList);
733 if (dwFilesFound != dwFileCount)
740 extractDest.flags |= EXTRACT_FILLFILELIST;
742 extractDest.flags |= EXTRACT_EXTRACTFILES;
743 res = pExtract(&extractDest, CabName);
745 if (extractDest.filelist)
747 struct ExtractFileList* curr = extractDest.filelist;
748 struct ExtractFileList* next;
753 free_file_node(curr);
759 FreeLibrary(hCabinet);
760 HeapFree(GetProcessHeap(), 0, szConvertedList);
765 /***********************************************************************
766 * FileSaveMarkNotExistA (ADVPACK.@)
768 * See FileSaveMarkNotExistW.
770 HRESULT WINAPI FileSaveMarkNotExistA(LPSTR pszFileList, LPSTR pszDir, LPSTR pszBaseName)
772 TRACE("(%s, %s, %s)\n", debugstr_a(pszFileList),
773 debugstr_a(pszDir), debugstr_a(pszBaseName));
775 return AddDelBackupEntryA(pszFileList, pszDir, pszBaseName, AADBE_DEL_ENTRY);
778 /***********************************************************************
779 * FileSaveMarkNotExistW (ADVPACK.@)
781 * Marks the files in the file list as not existing so they won't be
782 * backed up during a save.
785 * pszFileList [I] NULL-separated list of filenames.
786 * pszDir [I] Path of the backup directory.
787 * pszBaseName [I] Basename of the INI file.
793 HRESULT WINAPI FileSaveMarkNotExistW(LPWSTR pszFileList, LPWSTR pszDir, LPWSTR pszBaseName)
795 TRACE("(%s, %s, %s)\n", debugstr_w(pszFileList),
796 debugstr_w(pszDir), debugstr_w(pszBaseName));
798 return AddDelBackupEntryW(pszFileList, pszDir, pszBaseName, AADBE_DEL_ENTRY);
801 /***********************************************************************
802 * FileSaveRestoreA (ADVPACK.@)
804 * See FileSaveRestoreW.
806 HRESULT WINAPI FileSaveRestoreA(HWND hDlg, LPSTR pszFileList, LPSTR pszDir,
807 LPSTR pszBaseName, DWORD dwFlags)
809 UNICODE_STRING filelist, dir, basename;
812 TRACE("(%p, %s, %s, %s, %d)\n", hDlg, debugstr_a(pszFileList),
813 debugstr_a(pszDir), debugstr_a(pszBaseName), dwFlags);
815 RtlCreateUnicodeStringFromAsciiz(&filelist, pszFileList);
816 RtlCreateUnicodeStringFromAsciiz(&dir, pszDir);
817 RtlCreateUnicodeStringFromAsciiz(&basename, pszBaseName);
819 hr = FileSaveRestoreW(hDlg, filelist.Buffer, dir.Buffer,
820 basename.Buffer, dwFlags);
822 RtlFreeUnicodeString(&filelist);
823 RtlFreeUnicodeString(&dir);
824 RtlFreeUnicodeString(&basename);
829 /***********************************************************************
830 * FileSaveRestoreW (ADVPACK.@)
832 * Saves or restores the files in the specified file list.
835 * hDlg [I] Handle to the dialog used for the display.
836 * pszFileList [I] NULL-separated list of filenames.
837 * pszDir [I] Path of the backup directory.
838 * pszBaseName [I] Basename of the backup files.
839 * dwFlags [I] See advpub.h.
846 * If pszFileList is NULL on restore, all files will be restored.
851 HRESULT WINAPI FileSaveRestoreW(HWND hDlg, LPWSTR pszFileList, LPWSTR pszDir,
852 LPWSTR pszBaseName, DWORD dwFlags)
854 FIXME("(%p, %s, %s, %s, %d) stub\n", hDlg, debugstr_w(pszFileList),
855 debugstr_w(pszDir), debugstr_w(pszBaseName), dwFlags);
860 /***********************************************************************
861 * FileSaveRestoreOnINFA (ADVPACK.@)
863 * See FileSaveRestoreOnINFW.
865 HRESULT WINAPI FileSaveRestoreOnINFA(HWND hWnd, LPCSTR pszTitle, LPCSTR pszINF,
866 LPCSTR pszSection, LPCSTR pszBackupDir,
867 LPCSTR pszBaseBackupFile, DWORD dwFlags)
869 UNICODE_STRING title, inf, section;
870 UNICODE_STRING backupdir, backupfile;
873 TRACE("(%p, %s, %s, %s, %s, %s, %d)\n", hWnd, debugstr_a(pszTitle),
874 debugstr_a(pszINF), debugstr_a(pszSection), debugstr_a(pszBackupDir),
875 debugstr_a(pszBaseBackupFile), dwFlags);
877 RtlCreateUnicodeStringFromAsciiz(&title, pszTitle);
878 RtlCreateUnicodeStringFromAsciiz(&inf, pszINF);
879 RtlCreateUnicodeStringFromAsciiz(§ion, pszSection);
880 RtlCreateUnicodeStringFromAsciiz(&backupdir, pszBackupDir);
881 RtlCreateUnicodeStringFromAsciiz(&backupfile, pszBaseBackupFile);
883 hr = FileSaveRestoreOnINFW(hWnd, title.Buffer, inf.Buffer, section.Buffer,
884 backupdir.Buffer, backupfile.Buffer, dwFlags);
886 RtlFreeUnicodeString(&title);
887 RtlFreeUnicodeString(&inf);
888 RtlFreeUnicodeString(§ion);
889 RtlFreeUnicodeString(&backupdir);
890 RtlFreeUnicodeString(&backupfile);
895 /***********************************************************************
896 * FileSaveRestoreOnINFW (ADVPACK.@)
900 * hWnd [I] Handle to the window used for the display.
901 * pszTitle [I] Title of the window.
902 * pszINF [I] Fully-qualified INF filename.
903 * pszSection [I] GenInstall INF section name.
904 * pszBackupDir [I] Directory to store the backup file.
905 * pszBaseBackupFile [I] Basename of the backup files.
906 * dwFlags [I] See advpub.h
913 * If pszSection is NULL, the default section will be used.
918 HRESULT WINAPI FileSaveRestoreOnINFW(HWND hWnd, LPCWSTR pszTitle, LPCWSTR pszINF,
919 LPCWSTR pszSection, LPCWSTR pszBackupDir,
920 LPCWSTR pszBaseBackupFile, DWORD dwFlags)
922 FIXME("(%p, %s, %s, %s, %s, %s, %d): stub\n", hWnd, debugstr_w(pszTitle),
923 debugstr_w(pszINF), debugstr_w(pszSection), debugstr_w(pszBackupDir),
924 debugstr_w(pszBaseBackupFile), dwFlags);
929 /***********************************************************************
930 * GetVersionFromFileA (ADVPACK.@)
932 * See GetVersionFromFileExW.
934 HRESULT WINAPI GetVersionFromFileA(LPCSTR Filename, LPDWORD MajorVer,
935 LPDWORD MinorVer, BOOL Version )
937 TRACE("(%s, %p, %p, %d)\n", debugstr_a(Filename), MajorVer, MinorVer, Version);
938 return GetVersionFromFileExA(Filename, MajorVer, MinorVer, Version);
941 /***********************************************************************
942 * GetVersionFromFileW (ADVPACK.@)
944 * See GetVersionFromFileExW.
946 HRESULT WINAPI GetVersionFromFileW(LPCWSTR Filename, LPDWORD MajorVer,
947 LPDWORD MinorVer, BOOL Version )
949 TRACE("(%s, %p, %p, %d)\n", debugstr_w(Filename), MajorVer, MinorVer, Version);
950 return GetVersionFromFileExW(Filename, MajorVer, MinorVer, Version);
953 /* data for GetVersionFromFileEx */
954 typedef struct tagLANGANDCODEPAGE
960 /***********************************************************************
961 * GetVersionFromFileExA (ADVPACK.@)
963 * See GetVersionFromFileExW.
965 HRESULT WINAPI GetVersionFromFileExA(LPCSTR lpszFilename, LPDWORD pdwMSVer,
966 LPDWORD pdwLSVer, BOOL bVersion )
968 UNICODE_STRING filename;
971 TRACE("(%s, %p, %p, %d)\n", debugstr_a(lpszFilename),
972 pdwMSVer, pdwLSVer, bVersion);
974 RtlCreateUnicodeStringFromAsciiz(&filename, lpszFilename);
976 res = GetVersionFromFileExW(filename.Buffer, pdwMSVer, pdwLSVer, bVersion);
978 RtlFreeUnicodeString(&filename);
983 /***********************************************************************
984 * GetVersionFromFileExW (ADVPACK.@)
986 * Gets the files version or language information.
989 * lpszFilename [I] The file to get the info from.
990 * pdwMSVer [O] Major version.
991 * pdwLSVer [O] Minor version.
992 * bVersion [I] Whether to retrieve version or language info.
995 * Always returns S_OK.
998 * If bVersion is TRUE, version information is retrieved, else
999 * pdwMSVer gets the language ID and pdwLSVer gets the codepage ID.
1001 HRESULT WINAPI GetVersionFromFileExW(LPCWSTR lpszFilename, LPDWORD pdwMSVer,
1002 LPDWORD pdwLSVer, BOOL bVersion )
1004 VS_FIXEDFILEINFO *pFixedVersionInfo;
1005 LANGANDCODEPAGE *pLangAndCodePage;
1006 DWORD dwHandle, dwInfoSize;
1007 WCHAR szWinDir[MAX_PATH];
1008 WCHAR szFile[MAX_PATH];
1009 LPVOID pVersionInfo = NULL;
1010 BOOL bFileCopied = FALSE;
1013 static WCHAR backslash[] = {'\\',0};
1014 static WCHAR translation[] = {
1015 '\\','V','a','r','F','i','l','e','I','n','f','o',
1016 '\\','T','r','a','n','s','l','a','t','i','o','n',0
1019 TRACE("(%s, %p, %p, %d)\n", debugstr_w(lpszFilename),
1020 pdwMSVer, pdwLSVer, bVersion);
1025 lstrcpynW(szFile, lpszFilename, MAX_PATH);
1027 dwInfoSize = GetFileVersionInfoSizeW(szFile, &dwHandle);
1030 /* check that the file exists */
1031 if (GetFileAttributesW(szFile) == INVALID_FILE_ATTRIBUTES)
1034 /* file exists, but won't be found by GetFileVersionInfoSize,
1035 * so copy it to the temp dir where it will be found.
1037 GetWindowsDirectoryW(szWinDir, MAX_PATH);
1038 GetTempFileNameW(szWinDir, NULL, 0, szFile);
1039 CopyFileW(lpszFilename, szFile, FALSE);
1042 dwInfoSize = GetFileVersionInfoSizeW(szFile, &dwHandle);
1047 pVersionInfo = HeapAlloc(GetProcessHeap(), 0, dwInfoSize);
1051 if (!GetFileVersionInfoW(szFile, dwHandle, dwInfoSize, pVersionInfo))
1056 if (!VerQueryValueW(pVersionInfo, backslash,
1057 (LPVOID *)&pFixedVersionInfo, &uValueLen))
1063 *pdwMSVer = pFixedVersionInfo->dwFileVersionMS;
1064 *pdwLSVer = pFixedVersionInfo->dwFileVersionLS;
1068 if (!VerQueryValueW(pVersionInfo, translation,
1069 (LPVOID *)&pLangAndCodePage, &uValueLen))
1075 *pdwMSVer = pLangAndCodePage->wLanguage;
1076 *pdwLSVer = pLangAndCodePage->wCodePage;
1080 HeapFree(GetProcessHeap(), 0, pVersionInfo);
1083 DeleteFileW(szFile);