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 LPWSTR 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 = (LPWSTR)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 szPath, szDestFilename;
253 WCHAR szRootPath[ROOT_LENGTH];
254 DWORD dwLen, dwLastError;
258 TRACE("(%p, %s, %s, %s, %s, %ld, %ld)\n", hwnd, debugstr_w(lpszSourceDir),
259 debugstr_w(lpszSourceFile), debugstr_w(lpszDestDir),
260 debugstr_w(lpszDestFile), dwFlags, dwReserved);
262 if (!lpszSourceDir || !lpszSourceFile || !lpszDestDir)
265 fileQueue = SetupOpenFileQueue();
266 if (fileQueue == INVALID_HANDLE_VALUE)
267 return HRESULT_FROM_WIN32(GetLastError());
270 dwLastError = ERROR_SUCCESS;
272 lstrcpynW(szRootPath, lpszSourceDir, ROOT_LENGTH);
273 szPath = (LPWSTR)lpszSourceDir + ROOT_LENGTH;
275 /* use lpszSourceFile as destination filename if lpszDestFile is NULL */
278 dwLen = lstrlenW(lpszDestFile);
279 szDestFilename = HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(WCHAR));
280 lstrcpyW(szDestFilename, lpszDestFile);
284 dwLen = lstrlenW(lpszSourceFile);
285 szDestFilename = HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(WCHAR));
286 lstrcpyW(szDestFilename, lpszSourceFile);
289 /* add the file copy operation to the setup queue */
290 if (!SetupQueueCopyW(fileQueue, szRootPath, szPath, lpszSourceFile, NULL,
291 NULL, lpszDestDir, szDestFilename, dwFlags))
293 dwLastError = GetLastError();
297 pContext = SetupInitDefaultQueueCallbackEx(hwnd, INVALID_HANDLE_VALUE,
301 dwLastError = GetLastError();
305 /* don't output anything for AIF_QUIET */
306 if (dwFlags & AIF_QUIET)
307 pFileCallback = pQuietQueueCallback;
309 pFileCallback = pQueueCallback;
311 /* perform the file copy */
312 if (!SetupCommitFileQueueW(hwnd, fileQueue, pFileCallback, pContext))
314 dwLastError = GetLastError();
319 SetupTermDefaultQueueCallback(pContext);
320 SetupCloseFileQueue(fileQueue);
322 HeapFree(GetProcessHeap(), 0, szDestFilename);
324 return HRESULT_FROM_WIN32(dwLastError);
327 static HRESULT DELNODE_recurse_dirtree(LPWSTR fname, DWORD flags)
329 DWORD fattrs = GetFileAttributesW(fname);
330 HRESULT ret = E_FAIL;
332 static const WCHAR backslash[] = {'\\',0};
333 static const WCHAR asterisk[] = {'*',0};
334 static const WCHAR dot[] = {'.',0};
335 static const WCHAR dotdot[] = {'.','.',0};
337 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
340 WIN32_FIND_DATAW w32fd;
342 int fname_len = lstrlenW(fname);
344 /* Generate a path with wildcard suitable for iterating */
345 if (lstrcmpW(CharPrevW(fname, fname + fname_len), backslash))
347 lstrcpyW(fname + fname_len, backslash);
350 lstrcpyW(fname + fname_len, asterisk);
352 if ((hFindFile = FindFirstFileW(fname, &w32fd)) != INVALID_HANDLE_VALUE)
354 /* Iterate through the files in the directory */
355 for (done = FALSE; !done; done = !FindNextFileW(hFindFile, &w32fd))
357 TRACE("%s\n", debugstr_w(w32fd.cFileName));
358 if (lstrcmpW(dot, w32fd.cFileName) != 0 &&
359 lstrcmpW(dotdot, w32fd.cFileName) != 0)
361 lstrcpyW(fname + fname_len, w32fd.cFileName);
362 if (DELNODE_recurse_dirtree(fname, flags) != S_OK)
368 FindClose(hFindFile);
371 /* We're done with this directory, so restore the old path without wildcard */
372 *(fname + fname_len) = '\0';
376 TRACE("%s: directory\n", debugstr_w(fname));
377 if (SetFileAttributesW(fname, FILE_ATTRIBUTE_NORMAL) && RemoveDirectoryW(fname))
385 TRACE("%s: file\n", debugstr_w(fname));
386 if (SetFileAttributesW(fname, FILE_ATTRIBUTE_NORMAL) && DeleteFileW(fname))
395 /***********************************************************************
396 * DelNodeA (ADVPACK.@)
400 HRESULT WINAPI DelNodeA(LPCSTR pszFileOrDirName, DWORD dwFlags)
402 UNICODE_STRING fileordirname;
405 TRACE("(%s, %ld)\n", debugstr_a(pszFileOrDirName), dwFlags);
407 RtlCreateUnicodeStringFromAsciiz(&fileordirname, pszFileOrDirName);
409 res = DelNodeW(fileordirname.Buffer, dwFlags);
411 RtlFreeUnicodeString(&fileordirname);
416 /***********************************************************************
417 * DelNodeW (ADVPACK.@)
419 * Deletes a file or directory
422 * pszFileOrDirName [I] Name of file or directory to delete
423 * dwFlags [I] Flags; see include/advpub.h
431 * - Native version apparently does a lot of checking to make sure
432 * we're not trying to delete a system directory etc.
434 HRESULT WINAPI DelNodeW(LPCWSTR pszFileOrDirName, DWORD dwFlags)
436 WCHAR fname[MAX_PATH];
437 HRESULT ret = E_FAIL;
439 TRACE("(%s, %ld)\n", debugstr_w(pszFileOrDirName), dwFlags);
442 FIXME("Flags ignored!\n");
444 if (pszFileOrDirName && *pszFileOrDirName)
446 lstrcpyW(fname, pszFileOrDirName);
448 /* TODO: Should check for system directory deletion etc. here */
450 ret = DELNODE_recurse_dirtree(fname, dwFlags);
456 /***********************************************************************
457 * DelNodeRunDLL32A (ADVPACK.@)
459 * See DelNodeRunDLL32W.
461 HRESULT WINAPI DelNodeRunDLL32A(HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show)
463 UNICODE_STRING params;
466 TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_a(cmdline), show);
468 RtlCreateUnicodeStringFromAsciiz(¶ms, cmdline);
470 hr = DelNodeRunDLL32W(hWnd, hInst, params.Buffer, show);
472 RtlFreeUnicodeString(¶ms);
477 /***********************************************************************
478 * DelNodeRunDLL32W (ADVPACK.@)
480 * Deletes a file or directory, WinMain style.
483 * hWnd [I] Handle to the window used for the display.
484 * hInst [I] Instance of the process.
485 * cmdline [I] Contains parameters in the order FileOrDirName,Flags.
486 * show [I] How the window should be shown.
492 HRESULT WINAPI DelNodeRunDLL32W(HWND hWnd, HINSTANCE hInst, LPWSTR cmdline, INT show)
494 LPWSTR szFilename, szFlags;
495 LPWSTR cmdline_copy, cmdline_ptr;
499 TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_w(cmdline), show);
501 cmdline_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(cmdline) + 1) * sizeof(WCHAR));
502 cmdline_ptr = cmdline_copy;
503 lstrcpyW(cmdline_copy, cmdline);
505 /* get the parameters at indexes 0 and 1 respectively */
506 szFilename = get_parameter(&cmdline_ptr, ',');
507 szFlags = get_parameter(&cmdline_ptr, ',');
510 dwFlags = atolW(szFlags);
512 res = DelNodeW(szFilename, dwFlags);
514 HeapFree(GetProcessHeap(), 0, cmdline_copy);
519 /* The following defintions were copied from dlls/cabinet/cabinet.h */
521 /* EXTRACTdest flags */
522 #define EXTRACT_FILLFILELIST 0x00000001
523 #define EXTRACT_EXTRACTFILES 0x00000002
525 struct ExtractFileList {
527 struct ExtractFileList *next;
528 BOOL unknown; /* always 1L */
531 /* the first parameter of the function Extract */
533 long result1; /* 0x000 */
534 long unknown1[3]; /* 0x004 */
535 struct ExtractFileList *filelist; /* 0x010 */
536 long filecount; /* 0x014 */
537 DWORD flags; /* 0x018 */
538 char directory[0x104]; /* 0x01c */
539 char lastfile[0x20c]; /* 0x120 */
542 static HRESULT (WINAPI *pExtract)(EXTRACTdest*, LPCSTR);
544 /* removes legal characters before and after file list, and
545 * converts the file list to a NULL-separated list
547 static LPSTR convert_file_list(LPCSTR FileList, DWORD *dwNumFiles)
550 char *first = (char *)FileList;
551 char *last = (char *)FileList + strlen(FileList) - 1;
552 LPSTR szConvertedList, temp;
554 /* any number of these chars before the list is OK */
555 while (first < last && (*first == ' ' || *first == '\t' || *first == ':'))
558 /* any number of these chars after the list is OK */
559 while (last > first && (*last == ' ' || *last == '\t' || *last == ':'))
565 dwLen = last - first + 3; /* room for double-null termination */
566 szConvertedList = HeapAlloc(GetProcessHeap(), 0, dwLen);
567 lstrcpynA(szConvertedList, first, dwLen - 1);
569 szConvertedList[dwLen - 1] = '\0';
570 szConvertedList[dwLen] = '\0';
573 if (!lstrlenA(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(LPSTR szFile, LPSTR 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, LPSTR 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, %ld, %s, %p, %ld)\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);
746 FreeLibrary(hCabinet);
747 HeapFree(GetProcessHeap(), 0, szConvertedList);
752 /***********************************************************************
753 * FileSaveMarkNotExistA (ADVPACK.@)
755 * See FileSaveMarkNotExistW.
757 HRESULT WINAPI FileSaveMarkNotExistA(LPSTR pszFileList, LPSTR pszDir, LPSTR pszBaseName)
759 TRACE("(%s, %s, %s)\n", debugstr_a(pszFileList),
760 debugstr_a(pszDir), debugstr_a(pszBaseName));
762 return AddDelBackupEntryA(pszFileList, pszDir, pszBaseName, AADBE_DEL_ENTRY);
765 /***********************************************************************
766 * FileSaveMarkNotExistW (ADVPACK.@)
768 * Marks the files in the file list as not existing so they won't be
769 * backed up during a save.
772 * pszFileList [I] NULL-separated list of filenames.
773 * pszDir [I] Path of the backup directory.
774 * pszBaseName [I] Basename of the INI file.
780 HRESULT WINAPI FileSaveMarkNotExistW(LPWSTR pszFileList, LPWSTR pszDir, LPWSTR pszBaseName)
782 TRACE("(%s, %s, %s)\n", debugstr_w(pszFileList),
783 debugstr_w(pszDir), debugstr_w(pszBaseName));
785 return AddDelBackupEntryW(pszFileList, pszDir, pszBaseName, AADBE_DEL_ENTRY);
788 /***********************************************************************
789 * FileSaveRestoreA (ADVPACK.@)
791 * See FileSaveRestoreW.
793 HRESULT WINAPI FileSaveRestoreA(HWND hDlg, LPSTR pszFileList, LPSTR pszDir,
794 LPSTR pszBaseName, DWORD dwFlags)
796 UNICODE_STRING filelist, dir, basename;
799 TRACE("(%p, %s, %s, %s, %ld)\n", hDlg, debugstr_a(pszFileList),
800 debugstr_a(pszDir), debugstr_a(pszBaseName), dwFlags);
802 RtlCreateUnicodeStringFromAsciiz(&filelist, pszFileList);
803 RtlCreateUnicodeStringFromAsciiz(&dir, pszDir);
804 RtlCreateUnicodeStringFromAsciiz(&basename, pszBaseName);
806 hr = FileSaveRestoreW(hDlg, filelist.Buffer, dir.Buffer,
807 basename.Buffer, dwFlags);
809 RtlFreeUnicodeString(&filelist);
810 RtlFreeUnicodeString(&dir);
811 RtlFreeUnicodeString(&basename);
816 /***********************************************************************
817 * FileSaveRestoreW (ADVPACK.@)
819 * Saves or restores the files in the specified file list.
822 * hDlg [I] Handle to the dialog used for the display.
823 * pszFileList [I] NULL-separated list of filenames.
824 * pszDir [I] Path of the backup directory.
825 * pszBaseName [I] Basename of the backup files.
826 * dwFlags [I] See advpub.h.
833 * If pszFileList is NULL on restore, all files will be restored.
838 HRESULT WINAPI FileSaveRestoreW(HWND hDlg, LPWSTR pszFileList, LPWSTR pszDir,
839 LPWSTR pszBaseName, DWORD dwFlags)
841 FIXME("(%p, %s, %s, %s, %ld) stub\n", hDlg, debugstr_w(pszFileList),
842 debugstr_w(pszDir), debugstr_w(pszBaseName), dwFlags);
847 /***********************************************************************
848 * FileSaveRestoreOnINFA (ADVPACK.@)
850 * See FileSaveRestoreOnINFW.
852 HRESULT WINAPI FileSaveRestoreOnINFA(HWND hWnd, LPCSTR pszTitle, LPCSTR pszINF,
853 LPCSTR pszSection, LPCSTR pszBackupDir,
854 LPCSTR pszBaseBackupFile, DWORD dwFlags)
856 UNICODE_STRING title, inf, section;
857 UNICODE_STRING backupdir, backupfile;
860 TRACE("(%p, %s, %s, %s, %s, %s, %ld)\n", hWnd, debugstr_a(pszTitle),
861 debugstr_a(pszINF), debugstr_a(pszSection), debugstr_a(pszBackupDir),
862 debugstr_a(pszBaseBackupFile), dwFlags);
864 RtlCreateUnicodeStringFromAsciiz(&title, pszTitle);
865 RtlCreateUnicodeStringFromAsciiz(&inf, pszINF);
866 RtlCreateUnicodeStringFromAsciiz(§ion, pszSection);
867 RtlCreateUnicodeStringFromAsciiz(&backupdir, pszBackupDir);
868 RtlCreateUnicodeStringFromAsciiz(&backupfile, pszBaseBackupFile);
870 hr = FileSaveRestoreOnINFW(hWnd, title.Buffer, inf.Buffer, section.Buffer,
871 backupdir.Buffer, backupfile.Buffer, dwFlags);
873 RtlFreeUnicodeString(&title);
874 RtlFreeUnicodeString(&inf);
875 RtlFreeUnicodeString(§ion);
876 RtlFreeUnicodeString(&backupdir);
877 RtlFreeUnicodeString(&backupfile);
882 /***********************************************************************
883 * FileSaveRestoreOnINFW (ADVPACK.@)
887 * hWnd [I] Handle to the window used for the display.
888 * pszTitle [I] Title of the window.
889 * pszINF [I] Fully-qualified INF filename.
890 * pszSection [I] GenInstall INF section name.
891 * pszBackupDir [I] Directory to store the backup file.
892 * pszBaseBackupFile [I] Basename of the backup files.
893 * dwFlags [I] See advpub.h
900 * If pszSection is NULL, the default section will be used.
905 HRESULT WINAPI FileSaveRestoreOnINFW(HWND hWnd, LPCWSTR pszTitle, LPCWSTR pszINF,
906 LPCWSTR pszSection, LPCWSTR pszBackupDir,
907 LPCWSTR pszBaseBackupFile, DWORD dwFlags)
909 FIXME("(%p, %s, %s, %s, %s, %s, %ld): stub\n", hWnd, debugstr_w(pszTitle),
910 debugstr_w(pszINF), debugstr_w(pszSection), debugstr_w(pszBackupDir),
911 debugstr_w(pszBaseBackupFile), dwFlags);
916 /***********************************************************************
917 * GetVersionFromFileA (ADVPACK.@)
919 * See GetVersionFromFileExW.
921 HRESULT WINAPI GetVersionFromFileA(LPCSTR Filename, LPDWORD MajorVer,
922 LPDWORD MinorVer, BOOL Version )
924 TRACE("(%s, %p, %p, %d)\n", debugstr_a(Filename), MajorVer, MinorVer, Version);
925 return GetVersionFromFileExA(Filename, MajorVer, MinorVer, Version);
928 /***********************************************************************
929 * GetVersionFromFileW (ADVPACK.@)
931 * See GetVersionFromFileExW.
933 HRESULT WINAPI GetVersionFromFileW(LPCWSTR Filename, LPDWORD MajorVer,
934 LPDWORD MinorVer, BOOL Version )
936 TRACE("(%s, %p, %p, %d)\n", debugstr_w(Filename), MajorVer, MinorVer, Version);
937 return GetVersionFromFileExW(Filename, MajorVer, MinorVer, Version);
940 /* data for GetVersionFromFileEx */
941 typedef struct tagLANGANDCODEPAGE
947 /***********************************************************************
948 * GetVersionFromFileExA (ADVPACK.@)
950 * See GetVersionFromFileExW.
952 HRESULT WINAPI GetVersionFromFileExA(LPCSTR lpszFilename, LPDWORD pdwMSVer,
953 LPDWORD pdwLSVer, BOOL bVersion )
955 UNICODE_STRING filename;
958 TRACE("(%s, %p, %p, %d)\n", debugstr_a(lpszFilename),
959 pdwMSVer, pdwLSVer, bVersion);
961 RtlCreateUnicodeStringFromAsciiz(&filename, lpszFilename);
963 res = GetVersionFromFileExW(filename.Buffer, pdwMSVer, pdwLSVer, bVersion);
965 RtlFreeUnicodeString(&filename);
970 /***********************************************************************
971 * GetVersionFromFileExW (ADVPACK.@)
973 * Gets the files version or language information.
976 * lpszFilename [I] The file to get the info from.
977 * pdwMSVer [O] Major version.
978 * pdwLSVer [O] Minor version.
979 * bVersion [I] Whether to retrieve version or language info.
982 * Always returns S_OK.
985 * If bVersion is TRUE, version information is retrieved, else
986 * pdwMSVer gets the language ID and pdwLSVer gets the codepage ID.
988 HRESULT WINAPI GetVersionFromFileExW(LPCWSTR lpszFilename, LPDWORD pdwMSVer,
989 LPDWORD pdwLSVer, BOOL bVersion )
991 VS_FIXEDFILEINFO *pFixedVersionInfo;
992 LANGANDCODEPAGE *pLangAndCodePage;
993 DWORD dwHandle, dwInfoSize;
994 WCHAR szWinDir[MAX_PATH];
995 WCHAR szFile[MAX_PATH];
996 LPVOID pVersionInfo = NULL;
997 BOOL bFileCopied = FALSE;
1000 static WCHAR backslash[] = {'\\',0};
1001 static WCHAR translation[] = {
1002 '\\','V','a','r','F','i','l','e','I','n','f','o',
1003 '\\','T','r','a','n','s','l','a','t','i','o','n',0
1006 TRACE("(%s, %p, %p, %d)\n", debugstr_w(lpszFilename),
1007 pdwMSVer, pdwLSVer, bVersion);
1012 lstrcpynW(szFile, lpszFilename, MAX_PATH);
1014 dwInfoSize = GetFileVersionInfoSizeW(szFile, &dwHandle);
1017 /* check that the file exists */
1018 if (GetFileAttributesW(szFile) == INVALID_FILE_ATTRIBUTES)
1021 /* file exists, but won't be found by GetFileVersionInfoSize,
1022 * so copy it to the temp dir where it will be found.
1024 GetWindowsDirectoryW(szWinDir, MAX_PATH);
1025 GetTempFileNameW(szWinDir, NULL, 0, szFile);
1026 CopyFileW(lpszFilename, szFile, FALSE);
1029 dwInfoSize = GetFileVersionInfoSizeW(szFile, &dwHandle);
1034 pVersionInfo = HeapAlloc(GetProcessHeap(), 0, dwInfoSize);
1038 if (!GetFileVersionInfoW(szFile, dwHandle, dwInfoSize, pVersionInfo))
1043 if (!VerQueryValueW(pVersionInfo, backslash,
1044 (LPVOID *)&pFixedVersionInfo, &uValueLen))
1050 *pdwMSVer = pFixedVersionInfo->dwFileVersionMS;
1051 *pdwLSVer = pFixedVersionInfo->dwFileVersionLS;
1055 if (!VerQueryValueW(pVersionInfo, translation,
1056 (LPVOID *)&pLangAndCodePage, &uValueLen))
1062 *pdwMSVer = pLangAndCodePage->wLanguage;
1063 *pdwLSVer = pLangAndCodePage->wCodePage;
1067 HeapFree(GetProcessHeap(), 0, pVersionInfo);
1070 DeleteFileW(szFile);