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))
580 /* convert the colons to double-null termination */
581 temp = szConvertedList;
593 return szConvertedList;
596 static void free_file_node(struct ExtractFileList *pNode)
598 HeapFree(GetProcessHeap(), 0, pNode->filename);
599 HeapFree(GetProcessHeap(), 0, pNode);
602 /* determines whether szFile is in the NULL-separated szFileList */
603 static BOOL file_in_list(LPSTR szFile, LPSTR szFileList)
605 DWORD dwLen = lstrlenA(szFile);
610 dwTestLen = lstrlenA(szFileList);
612 if (dwTestLen == dwLen)
614 if (!lstrcmpiA(szFile, szFileList))
618 szFileList += dwTestLen + 1;
624 /* removes nodes from the linked list that aren't specified in szFileList
625 * returns the number of files that are in both the linked list and szFileList
627 static DWORD fill_file_list(EXTRACTdest *extractDest, LPCSTR szCabName, LPSTR szFileList)
629 DWORD dwNumFound = 0;
630 struct ExtractFileList *pNode;
631 struct ExtractFileList *prev = NULL;
633 extractDest->flags |= EXTRACT_FILLFILELIST;
634 if (pExtract(extractDest, szCabName))
636 extractDest->flags &= ~EXTRACT_FILLFILELIST;
640 pNode = extractDest->filelist;
643 if (file_in_list(pNode->filename, szFileList))
651 prev->next = pNode->next;
652 free_file_node(pNode);
657 extractDest->filelist = pNode->next;
658 free_file_node(pNode);
659 pNode = extractDest->filelist;
663 extractDest->flags &= ~EXTRACT_FILLFILELIST;
667 /***********************************************************************
668 * ExtractFilesA (ADVPACK.@)
670 * Extracts the specified files from a cab archive into
671 * a destination directory.
674 * CabName [I] Filename of the cab archive.
675 * ExpandDir [I] Destination directory for the extracted files.
676 * Flags [I] Reserved.
677 * FileList [I] Optional list of files to extract. See NOTES.
678 * LReserved [I] Reserved. Must be NULL.
679 * Reserved [I] Reserved. Must be 0.
686 * FileList is a colon-separated list of filenames. If FileList is
687 * non-NULL, only the files in the list will be extracted from the
688 * cab file, otherwise all files will be extracted. Any number of
689 * spaces, tabs, or colons can be before or after the list, but
690 * the list itself must only be separated by colons.
692 HRESULT WINAPI ExtractFilesA(LPCSTR CabName, LPCSTR ExpandDir, DWORD Flags,
693 LPCSTR FileList, LPVOID LReserved, DWORD Reserved)
695 EXTRACTdest extractDest;
698 DWORD dwFileCount = 0;
699 DWORD dwFilesFound = 0;
700 LPSTR szConvertedList = NULL;
702 TRACE("(%s, %s, %d, %s, %p, %d)\n", debugstr_a(CabName), debugstr_a(ExpandDir),
703 Flags, debugstr_a(FileList), LReserved, Reserved);
705 if (!CabName || !ExpandDir)
708 if (GetFileAttributesA(ExpandDir) == INVALID_FILE_ATTRIBUTES)
709 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
711 hCabinet = LoadLibraryA("cabinet.dll");
715 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
722 ZeroMemory(&extractDest, sizeof(EXTRACTdest));
723 lstrcpyA(extractDest.directory, ExpandDir);
727 szConvertedList = convert_file_list(FileList, &dwFileCount);
728 if (!szConvertedList || dwFileCount == -1)
734 dwFilesFound = fill_file_list(&extractDest, CabName, szConvertedList);
735 if (dwFilesFound != dwFileCount)
742 extractDest.flags |= EXTRACT_FILLFILELIST;
744 extractDest.flags |= EXTRACT_EXTRACTFILES;
745 res = pExtract(&extractDest, CabName);
748 FreeLibrary(hCabinet);
749 HeapFree(GetProcessHeap(), 0, szConvertedList);
754 /***********************************************************************
755 * FileSaveMarkNotExistA (ADVPACK.@)
757 * See FileSaveMarkNotExistW.
759 HRESULT WINAPI FileSaveMarkNotExistA(LPSTR pszFileList, LPSTR pszDir, LPSTR pszBaseName)
761 TRACE("(%s, %s, %s)\n", debugstr_a(pszFileList),
762 debugstr_a(pszDir), debugstr_a(pszBaseName));
764 return AddDelBackupEntryA(pszFileList, pszDir, pszBaseName, AADBE_DEL_ENTRY);
767 /***********************************************************************
768 * FileSaveMarkNotExistW (ADVPACK.@)
770 * Marks the files in the file list as not existing so they won't be
771 * backed up during a save.
774 * pszFileList [I] NULL-separated list of filenames.
775 * pszDir [I] Path of the backup directory.
776 * pszBaseName [I] Basename of the INI file.
782 HRESULT WINAPI FileSaveMarkNotExistW(LPWSTR pszFileList, LPWSTR pszDir, LPWSTR pszBaseName)
784 TRACE("(%s, %s, %s)\n", debugstr_w(pszFileList),
785 debugstr_w(pszDir), debugstr_w(pszBaseName));
787 return AddDelBackupEntryW(pszFileList, pszDir, pszBaseName, AADBE_DEL_ENTRY);
790 /***********************************************************************
791 * FileSaveRestoreA (ADVPACK.@)
793 * See FileSaveRestoreW.
795 HRESULT WINAPI FileSaveRestoreA(HWND hDlg, LPSTR pszFileList, LPSTR pszDir,
796 LPSTR pszBaseName, DWORD dwFlags)
798 UNICODE_STRING filelist, dir, basename;
801 TRACE("(%p, %s, %s, %s, %d)\n", hDlg, debugstr_a(pszFileList),
802 debugstr_a(pszDir), debugstr_a(pszBaseName), dwFlags);
804 RtlCreateUnicodeStringFromAsciiz(&filelist, pszFileList);
805 RtlCreateUnicodeStringFromAsciiz(&dir, pszDir);
806 RtlCreateUnicodeStringFromAsciiz(&basename, pszBaseName);
808 hr = FileSaveRestoreW(hDlg, filelist.Buffer, dir.Buffer,
809 basename.Buffer, dwFlags);
811 RtlFreeUnicodeString(&filelist);
812 RtlFreeUnicodeString(&dir);
813 RtlFreeUnicodeString(&basename);
818 /***********************************************************************
819 * FileSaveRestoreW (ADVPACK.@)
821 * Saves or restores the files in the specified file list.
824 * hDlg [I] Handle to the dialog used for the display.
825 * pszFileList [I] NULL-separated list of filenames.
826 * pszDir [I] Path of the backup directory.
827 * pszBaseName [I] Basename of the backup files.
828 * dwFlags [I] See advpub.h.
835 * If pszFileList is NULL on restore, all files will be restored.
840 HRESULT WINAPI FileSaveRestoreW(HWND hDlg, LPWSTR pszFileList, LPWSTR pszDir,
841 LPWSTR pszBaseName, DWORD dwFlags)
843 FIXME("(%p, %s, %s, %s, %d) stub\n", hDlg, debugstr_w(pszFileList),
844 debugstr_w(pszDir), debugstr_w(pszBaseName), dwFlags);
849 /***********************************************************************
850 * FileSaveRestoreOnINFA (ADVPACK.@)
852 * See FileSaveRestoreOnINFW.
854 HRESULT WINAPI FileSaveRestoreOnINFA(HWND hWnd, LPCSTR pszTitle, LPCSTR pszINF,
855 LPCSTR pszSection, LPCSTR pszBackupDir,
856 LPCSTR pszBaseBackupFile, DWORD dwFlags)
858 UNICODE_STRING title, inf, section;
859 UNICODE_STRING backupdir, backupfile;
862 TRACE("(%p, %s, %s, %s, %s, %s, %d)\n", hWnd, debugstr_a(pszTitle),
863 debugstr_a(pszINF), debugstr_a(pszSection), debugstr_a(pszBackupDir),
864 debugstr_a(pszBaseBackupFile), dwFlags);
866 RtlCreateUnicodeStringFromAsciiz(&title, pszTitle);
867 RtlCreateUnicodeStringFromAsciiz(&inf, pszINF);
868 RtlCreateUnicodeStringFromAsciiz(§ion, pszSection);
869 RtlCreateUnicodeStringFromAsciiz(&backupdir, pszBackupDir);
870 RtlCreateUnicodeStringFromAsciiz(&backupfile, pszBaseBackupFile);
872 hr = FileSaveRestoreOnINFW(hWnd, title.Buffer, inf.Buffer, section.Buffer,
873 backupdir.Buffer, backupfile.Buffer, dwFlags);
875 RtlFreeUnicodeString(&title);
876 RtlFreeUnicodeString(&inf);
877 RtlFreeUnicodeString(§ion);
878 RtlFreeUnicodeString(&backupdir);
879 RtlFreeUnicodeString(&backupfile);
884 /***********************************************************************
885 * FileSaveRestoreOnINFW (ADVPACK.@)
889 * hWnd [I] Handle to the window used for the display.
890 * pszTitle [I] Title of the window.
891 * pszINF [I] Fully-qualified INF filename.
892 * pszSection [I] GenInstall INF section name.
893 * pszBackupDir [I] Directory to store the backup file.
894 * pszBaseBackupFile [I] Basename of the backup files.
895 * dwFlags [I] See advpub.h
902 * If pszSection is NULL, the default section will be used.
907 HRESULT WINAPI FileSaveRestoreOnINFW(HWND hWnd, LPCWSTR pszTitle, LPCWSTR pszINF,
908 LPCWSTR pszSection, LPCWSTR pszBackupDir,
909 LPCWSTR pszBaseBackupFile, DWORD dwFlags)
911 FIXME("(%p, %s, %s, %s, %s, %s, %d): stub\n", hWnd, debugstr_w(pszTitle),
912 debugstr_w(pszINF), debugstr_w(pszSection), debugstr_w(pszBackupDir),
913 debugstr_w(pszBaseBackupFile), dwFlags);
918 /***********************************************************************
919 * GetVersionFromFileA (ADVPACK.@)
921 * See GetVersionFromFileExW.
923 HRESULT WINAPI GetVersionFromFileA(LPCSTR Filename, LPDWORD MajorVer,
924 LPDWORD MinorVer, BOOL Version )
926 TRACE("(%s, %p, %p, %d)\n", debugstr_a(Filename), MajorVer, MinorVer, Version);
927 return GetVersionFromFileExA(Filename, MajorVer, MinorVer, Version);
930 /***********************************************************************
931 * GetVersionFromFileW (ADVPACK.@)
933 * See GetVersionFromFileExW.
935 HRESULT WINAPI GetVersionFromFileW(LPCWSTR Filename, LPDWORD MajorVer,
936 LPDWORD MinorVer, BOOL Version )
938 TRACE("(%s, %p, %p, %d)\n", debugstr_w(Filename), MajorVer, MinorVer, Version);
939 return GetVersionFromFileExW(Filename, MajorVer, MinorVer, Version);
942 /* data for GetVersionFromFileEx */
943 typedef struct tagLANGANDCODEPAGE
949 /***********************************************************************
950 * GetVersionFromFileExA (ADVPACK.@)
952 * See GetVersionFromFileExW.
954 HRESULT WINAPI GetVersionFromFileExA(LPCSTR lpszFilename, LPDWORD pdwMSVer,
955 LPDWORD pdwLSVer, BOOL bVersion )
957 UNICODE_STRING filename;
960 TRACE("(%s, %p, %p, %d)\n", debugstr_a(lpszFilename),
961 pdwMSVer, pdwLSVer, bVersion);
963 RtlCreateUnicodeStringFromAsciiz(&filename, lpszFilename);
965 res = GetVersionFromFileExW(filename.Buffer, pdwMSVer, pdwLSVer, bVersion);
967 RtlFreeUnicodeString(&filename);
972 /***********************************************************************
973 * GetVersionFromFileExW (ADVPACK.@)
975 * Gets the files version or language information.
978 * lpszFilename [I] The file to get the info from.
979 * pdwMSVer [O] Major version.
980 * pdwLSVer [O] Minor version.
981 * bVersion [I] Whether to retrieve version or language info.
984 * Always returns S_OK.
987 * If bVersion is TRUE, version information is retrieved, else
988 * pdwMSVer gets the language ID and pdwLSVer gets the codepage ID.
990 HRESULT WINAPI GetVersionFromFileExW(LPCWSTR lpszFilename, LPDWORD pdwMSVer,
991 LPDWORD pdwLSVer, BOOL bVersion )
993 VS_FIXEDFILEINFO *pFixedVersionInfo;
994 LANGANDCODEPAGE *pLangAndCodePage;
995 DWORD dwHandle, dwInfoSize;
996 WCHAR szWinDir[MAX_PATH];
997 WCHAR szFile[MAX_PATH];
998 LPVOID pVersionInfo = NULL;
999 BOOL bFileCopied = FALSE;
1002 static WCHAR backslash[] = {'\\',0};
1003 static WCHAR translation[] = {
1004 '\\','V','a','r','F','i','l','e','I','n','f','o',
1005 '\\','T','r','a','n','s','l','a','t','i','o','n',0
1008 TRACE("(%s, %p, %p, %d)\n", debugstr_w(lpszFilename),
1009 pdwMSVer, pdwLSVer, bVersion);
1014 lstrcpynW(szFile, lpszFilename, MAX_PATH);
1016 dwInfoSize = GetFileVersionInfoSizeW(szFile, &dwHandle);
1019 /* check that the file exists */
1020 if (GetFileAttributesW(szFile) == INVALID_FILE_ATTRIBUTES)
1023 /* file exists, but won't be found by GetFileVersionInfoSize,
1024 * so copy it to the temp dir where it will be found.
1026 GetWindowsDirectoryW(szWinDir, MAX_PATH);
1027 GetTempFileNameW(szWinDir, NULL, 0, szFile);
1028 CopyFileW(lpszFilename, szFile, FALSE);
1031 dwInfoSize = GetFileVersionInfoSizeW(szFile, &dwHandle);
1036 pVersionInfo = HeapAlloc(GetProcessHeap(), 0, dwInfoSize);
1040 if (!GetFileVersionInfoW(szFile, dwHandle, dwInfoSize, pVersionInfo))
1045 if (!VerQueryValueW(pVersionInfo, backslash,
1046 (LPVOID *)&pFixedVersionInfo, &uValueLen))
1052 *pdwMSVer = pFixedVersionInfo->dwFileVersionMS;
1053 *pdwLSVer = pFixedVersionInfo->dwFileVersionLS;
1057 if (!VerQueryValueW(pVersionInfo, translation,
1058 (LPVOID *)&pLangAndCodePage, &uValueLen))
1064 *pdwMSVer = pLangAndCodePage->wLanguage;
1065 *pdwLSVer = pLangAndCodePage->wCodePage;
1069 HeapFree(GetProcessHeap(), 0, pVersionInfo);
1072 DeleteFileW(szFile);