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
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
35 #include "advpack_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(advpack);
39 /* converts an ansi double null-terminated list to a unicode list */
40 static LPWSTR ansi_to_unicode_list(LPCSTR ansi_list)
44 LPCSTR ptr = ansi_list;
46 while (*ptr) ptr += lstrlenA(ptr) + 1;
47 len = ptr + 1 - ansi_list;
48 wlen = MultiByteToWideChar(CP_ACP, 0, ansi_list, len, NULL, 0);
49 list = HeapAlloc(GetProcessHeap(), 0, wlen * sizeof(WCHAR));
50 MultiByteToWideChar(CP_ACP, 0, ansi_list, len, list, wlen);
54 /***********************************************************************
55 * AddDelBackupEntryA (ADVPACK.@)
57 * See AddDelBackupEntryW.
59 HRESULT WINAPI AddDelBackupEntryA(LPCSTR lpcszFileList, LPCSTR lpcszBackupDir,
60 LPCSTR lpcszBaseName, DWORD dwFlags)
62 UNICODE_STRING backupdir, basename;
67 TRACE("(%s, %s, %s, %d)\n", debugstr_a(lpcszFileList),
68 debugstr_a(lpcszBackupDir), debugstr_a(lpcszBaseName), dwFlags);
71 filelist = ansi_to_unicode_list(lpcszFileList);
75 RtlCreateUnicodeStringFromAsciiz(&backupdir, lpcszBackupDir);
76 RtlCreateUnicodeStringFromAsciiz(&basename, lpcszBaseName);
79 backup = backupdir.Buffer;
83 res = AddDelBackupEntryW(filelist, backup, basename.Buffer, dwFlags);
85 HeapFree(GetProcessHeap(), 0, filelist);
87 RtlFreeUnicodeString(&backupdir);
88 RtlFreeUnicodeString(&basename);
93 /***********************************************************************
94 * AddDelBackupEntryW (ADVPACK.@)
96 * Either appends the files in the file list to the backup section of
97 * the specified INI, or deletes the entries from the INI file.
100 * lpcszFileList [I] NULL-separated list of filenames.
101 * lpcszBackupDir [I] Path of the backup directory.
102 * lpcszBaseName [I] Basename of the INI file.
103 * dwFlags [I] AADBE_ADD_ENTRY adds the entries in the file list
104 * to the INI file, while AADBE_DEL_ENTRY removes
105 * the entries from the INI file.
111 * If the INI file does not exist before adding entries to it, the file
114 * If lpcszBackupDir is NULL, the INI file is assumed to exist in
115 * c:\windows or created there if it does not exist.
117 HRESULT WINAPI AddDelBackupEntryW(LPCWSTR lpcszFileList, LPCWSTR lpcszBackupDir,
118 LPCWSTR lpcszBaseName, DWORD dwFlags)
120 WCHAR szIniPath[MAX_PATH];
121 LPCWSTR szString = NULL;
123 static const WCHAR szBackupEntry[] = {
124 '-','1',',','0',',','0',',','0',',','0',',','0',',','-','1',0
127 static const WCHAR backslash[] = {'\\',0};
128 static const WCHAR ini[] = {'.','i','n','i',0};
129 static const WCHAR backup[] = {'b','a','c','k','u','p',0};
131 TRACE("(%s, %s, %s, %d)\n", debugstr_w(lpcszFileList),
132 debugstr_w(lpcszBackupDir), debugstr_w(lpcszBaseName), dwFlags);
134 if (!lpcszFileList || !*lpcszFileList)
138 lstrcpyW(szIniPath, lpcszBackupDir);
140 GetWindowsDirectoryW(szIniPath, MAX_PATH);
142 lstrcatW(szIniPath, backslash);
143 lstrcatW(szIniPath, lpcszBaseName);
144 lstrcatW(szIniPath, ini);
146 SetFileAttributesW(szIniPath, FILE_ATTRIBUTE_NORMAL);
148 if (dwFlags & AADBE_ADD_ENTRY)
149 szString = szBackupEntry;
150 else if (dwFlags & AADBE_DEL_ENTRY)
153 /* add or delete the INI entries */
154 while (*lpcszFileList)
156 WritePrivateProfileStringW(backup, lpcszFileList, szString, szIniPath);
157 lpcszFileList += lstrlenW(lpcszFileList) + 1;
160 /* hide the INI file */
161 SetFileAttributesW(szIniPath, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN);
166 /* FIXME: this is only for the local case, X:\ */
167 #define ROOT_LENGTH 3
169 static UINT CALLBACK pQuietQueueCallback(PVOID Context, UINT Notification,
170 UINT_PTR Param1, UINT_PTR Param2)
175 static UINT CALLBACK pQueueCallback(PVOID Context, UINT Notification,
176 UINT_PTR Param1, UINT_PTR Param2)
178 /* only be verbose for error notifications */
180 Notification == SPFILENOTIFY_RENAMEERROR ||
181 Notification == SPFILENOTIFY_DELETEERROR ||
182 Notification == SPFILENOTIFY_COPYERROR)
184 return SetupDefaultQueueCallbackW(Context, Notification,
191 /***********************************************************************
192 * AdvInstallFileA (ADVPACK.@)
194 * See AdvInstallFileW.
196 HRESULT WINAPI AdvInstallFileA(HWND hwnd, LPCSTR lpszSourceDir, LPCSTR lpszSourceFile,
197 LPCSTR lpszDestDir, LPCSTR lpszDestFile,
198 DWORD dwFlags, DWORD dwReserved)
200 UNICODE_STRING sourcedir, sourcefile;
201 UNICODE_STRING destdir, destfile;
204 TRACE("(%p, %s, %s, %s, %s, %d, %d)\n", hwnd, debugstr_a(lpszSourceDir),
205 debugstr_a(lpszSourceFile), debugstr_a(lpszDestDir),
206 debugstr_a(lpszDestFile), dwFlags, dwReserved);
208 if (!lpszSourceDir || !lpszSourceFile || !lpszDestDir)
211 RtlCreateUnicodeStringFromAsciiz(&sourcedir, lpszSourceDir);
212 RtlCreateUnicodeStringFromAsciiz(&sourcefile, lpszSourceFile);
213 RtlCreateUnicodeStringFromAsciiz(&destdir, lpszDestDir);
214 RtlCreateUnicodeStringFromAsciiz(&destfile, lpszDestFile);
216 res = AdvInstallFileW(hwnd, sourcedir.Buffer, sourcefile.Buffer,
217 destdir.Buffer, destfile.Buffer, dwFlags, dwReserved);
219 RtlFreeUnicodeString(&sourcedir);
220 RtlFreeUnicodeString(&sourcefile);
221 RtlFreeUnicodeString(&destdir);
222 RtlFreeUnicodeString(&destfile);
227 /***********************************************************************
228 * AdvInstallFileW (ADVPACK.@)
230 * Copies a file from the source to a destination.
233 * hwnd [I] Handle to the window used for messages.
234 * lpszSourceDir [I] Source directory.
235 * lpszSourceFile [I] Source filename.
236 * lpszDestDir [I] Destination directory.
237 * lpszDestFile [I] Optional destination filename.
238 * dwFlags [I] See advpub.h.
239 * dwReserved [I] Reserved. Must be 0.
246 * If lpszDestFile is NULL, the destination filename is the same as
249 HRESULT WINAPI AdvInstallFileW(HWND hwnd, LPCWSTR lpszSourceDir, LPCWSTR lpszSourceFile,
250 LPCWSTR lpszDestDir, LPCWSTR lpszDestFile,
251 DWORD dwFlags, DWORD dwReserved)
253 PSP_FILE_CALLBACK_W pFileCallback;
254 LPWSTR szDestFilename;
256 WCHAR szRootPath[ROOT_LENGTH];
257 DWORD dwLen, dwLastError;
261 TRACE("(%p, %s, %s, %s, %s, %d, %d)\n", hwnd, debugstr_w(lpszSourceDir),
262 debugstr_w(lpszSourceFile), debugstr_w(lpszDestDir),
263 debugstr_w(lpszDestFile), dwFlags, dwReserved);
265 if (!lpszSourceDir || !lpszSourceFile || !lpszDestDir)
268 fileQueue = SetupOpenFileQueue();
269 if (fileQueue == INVALID_HANDLE_VALUE)
270 return HRESULT_FROM_WIN32(GetLastError());
273 dwLastError = ERROR_SUCCESS;
275 lstrcpynW(szRootPath, lpszSourceDir, ROOT_LENGTH);
276 szPath = lpszSourceDir + ROOT_LENGTH;
278 /* use lpszSourceFile as destination filename if lpszDestFile is NULL */
281 dwLen = lstrlenW(lpszDestFile);
282 szDestFilename = HeapAlloc(GetProcessHeap(), 0, (dwLen+1) * sizeof(WCHAR));
283 lstrcpyW(szDestFilename, lpszDestFile);
287 dwLen = lstrlenW(lpszSourceFile);
288 szDestFilename = HeapAlloc(GetProcessHeap(), 0, (dwLen+1) * sizeof(WCHAR));
289 lstrcpyW(szDestFilename, lpszSourceFile);
292 /* add the file copy operation to the setup queue */
293 if (!SetupQueueCopyW(fileQueue, szRootPath, szPath, lpszSourceFile, NULL,
294 NULL, lpszDestDir, szDestFilename, dwFlags))
296 dwLastError = GetLastError();
300 pContext = SetupInitDefaultQueueCallbackEx(hwnd, INVALID_HANDLE_VALUE,
304 dwLastError = GetLastError();
308 /* don't output anything for AIF_QUIET */
309 if (dwFlags & AIF_QUIET)
310 pFileCallback = pQuietQueueCallback;
312 pFileCallback = pQueueCallback;
314 /* perform the file copy */
315 if (!SetupCommitFileQueueW(hwnd, fileQueue, pFileCallback, pContext))
317 dwLastError = GetLastError();
322 SetupTermDefaultQueueCallback(pContext);
323 SetupCloseFileQueue(fileQueue);
325 HeapFree(GetProcessHeap(), 0, szDestFilename);
327 return HRESULT_FROM_WIN32(dwLastError);
330 static HRESULT DELNODE_recurse_dirtree(LPWSTR fname, DWORD flags)
332 DWORD fattrs = GetFileAttributesW(fname);
333 HRESULT ret = E_FAIL;
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 (fname_len && fname[fname_len-1] != '\\') fname[fname_len++] = '\\';
348 lstrcpyW(fname + fname_len, asterisk);
350 if ((hFindFile = FindFirstFileW(fname, &w32fd)) != INVALID_HANDLE_VALUE)
352 /* Iterate through the files in the directory */
353 for (done = FALSE; !done; done = !FindNextFileW(hFindFile, &w32fd))
355 TRACE("%s\n", debugstr_w(w32fd.cFileName));
356 if (lstrcmpW(dot, w32fd.cFileName) != 0 &&
357 lstrcmpW(dotdot, w32fd.cFileName) != 0)
359 lstrcpyW(fname + fname_len, w32fd.cFileName);
360 if (DELNODE_recurse_dirtree(fname, flags) != S_OK)
366 FindClose(hFindFile);
369 /* We're done with this directory, so restore the old path without wildcard */
370 *(fname + fname_len) = '\0';
374 TRACE("%s: directory\n", debugstr_w(fname));
375 if (SetFileAttributesW(fname, FILE_ATTRIBUTE_NORMAL) && RemoveDirectoryW(fname))
383 TRACE("%s: file\n", debugstr_w(fname));
384 if (SetFileAttributesW(fname, FILE_ATTRIBUTE_NORMAL) && DeleteFileW(fname))
393 /***********************************************************************
394 * DelNodeA (ADVPACK.@)
398 HRESULT WINAPI DelNodeA(LPCSTR pszFileOrDirName, DWORD dwFlags)
400 UNICODE_STRING fileordirname;
403 TRACE("(%s, %d)\n", debugstr_a(pszFileOrDirName), dwFlags);
405 RtlCreateUnicodeStringFromAsciiz(&fileordirname, pszFileOrDirName);
407 res = DelNodeW(fileordirname.Buffer, dwFlags);
409 RtlFreeUnicodeString(&fileordirname);
414 /***********************************************************************
415 * DelNodeW (ADVPACK.@)
417 * Deletes a file or directory
420 * pszFileOrDirName [I] Name of file or directory to delete
421 * dwFlags [I] Flags; see include/advpub.h
429 * - Native version apparently does a lot of checking to make sure
430 * we're not trying to delete a system directory etc.
432 HRESULT WINAPI DelNodeW(LPCWSTR pszFileOrDirName, DWORD dwFlags)
434 WCHAR fname[MAX_PATH];
435 HRESULT ret = E_FAIL;
437 TRACE("(%s, %d)\n", debugstr_w(pszFileOrDirName), dwFlags);
440 FIXME("Flags ignored!\n");
442 if (pszFileOrDirName && *pszFileOrDirName)
444 lstrcpyW(fname, pszFileOrDirName);
446 /* TODO: Should check for system directory deletion etc. here */
448 ret = DELNODE_recurse_dirtree(fname, dwFlags);
454 /***********************************************************************
455 * DelNodeRunDLL32A (ADVPACK.@)
457 * See DelNodeRunDLL32W.
459 HRESULT WINAPI DelNodeRunDLL32A(HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show)
461 UNICODE_STRING params;
464 TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_a(cmdline), show);
466 RtlCreateUnicodeStringFromAsciiz(¶ms, cmdline);
468 hr = DelNodeRunDLL32W(hWnd, hInst, params.Buffer, show);
470 RtlFreeUnicodeString(¶ms);
475 /***********************************************************************
476 * DelNodeRunDLL32W (ADVPACK.@)
478 * Deletes a file or directory, WinMain style.
481 * hWnd [I] Handle to the window used for the display.
482 * hInst [I] Instance of the process.
483 * cmdline [I] Contains parameters in the order FileOrDirName,Flags.
484 * show [I] How the window should be shown.
490 HRESULT WINAPI DelNodeRunDLL32W(HWND hWnd, HINSTANCE hInst, LPWSTR cmdline, INT show)
492 LPWSTR szFilename, szFlags;
493 LPWSTR cmdline_copy, cmdline_ptr;
497 TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_w(cmdline), show);
499 cmdline_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(cmdline) + 1) * sizeof(WCHAR));
500 cmdline_ptr = cmdline_copy;
501 lstrcpyW(cmdline_copy, cmdline);
503 /* get the parameters at indexes 0 and 1 respectively */
504 szFilename = get_parameter(&cmdline_ptr, ',');
505 szFlags = get_parameter(&cmdline_ptr, ',');
508 dwFlags = atolW(szFlags);
510 res = DelNodeW(szFilename, dwFlags);
512 HeapFree(GetProcessHeap(), 0, cmdline_copy);
517 /* The following definitions were copied from dlls/cabinet/cabinet.h */
519 /* SESSION Operation */
520 #define EXTRACT_FILLFILELIST 0x00000001
521 #define EXTRACT_EXTRACTFILES 0x00000002
525 struct FILELIST *next;
532 struct FILELIST *FileList;
535 CHAR Destination[MAX_PATH];
536 CHAR CurrentFile[MAX_PATH];
537 CHAR Reserved[MAX_PATH];
538 struct FILELIST *FilterList;
541 static HRESULT (WINAPI *pExtract)(SESSION*, LPCSTR);
543 /* removes legal characters before and after file list, and
544 * converts the file list to a NULL-separated list
546 static LPSTR convert_file_list(LPCSTR FileList, DWORD *dwNumFiles)
549 const char *first = FileList;
550 const char *last = FileList + strlen(FileList) - 1;
551 LPSTR szConvertedList, temp;
553 /* any number of these chars before the list is OK */
554 while (first < last && (*first == ' ' || *first == '\t' || *first == ':'))
557 /* any number of these chars after the list is OK */
558 while (last > first && (*last == ' ' || *last == '\t' || *last == ':'))
564 dwLen = last - first + 3; /* room for double-null termination */
565 szConvertedList = HeapAlloc(GetProcessHeap(), 0, dwLen);
566 lstrcpynA(szConvertedList, first, dwLen - 1);
567 szConvertedList[dwLen - 1] = '\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 FILELIST *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;
623 /* returns the number of files that are in both the linked list and szFileList */
624 static DWORD fill_file_list(SESSION *session, LPCSTR szCabName, LPCSTR szFileList)
626 DWORD dwNumFound = 0;
627 struct FILELIST *pNode;
629 session->Operation |= EXTRACT_FILLFILELIST;
630 if (pExtract(session, szCabName) != S_OK)
632 session->Operation &= ~EXTRACT_FILLFILELIST;
636 pNode = session->FileList;
639 if (!file_in_list(pNode->FileName, szFileList))
640 pNode->DoExtract = FALSE;
647 session->Operation &= ~EXTRACT_FILLFILELIST;
651 static void free_file_list(SESSION* session)
653 struct FILELIST *next, *curr = session->FileList;
658 free_file_node(curr);
663 /***********************************************************************
664 * ExtractFilesA (ADVPACK.@)
666 * Extracts the specified files from a cab archive into
667 * a destination directory.
670 * CabName [I] Filename of the cab archive.
671 * ExpandDir [I] Destination directory for the extracted files.
672 * Flags [I] Reserved.
673 * FileList [I] Optional list of files to extract. See NOTES.
674 * LReserved [I] Reserved. Must be NULL.
675 * Reserved [I] Reserved. Must be 0.
682 * FileList is a colon-separated list of filenames. If FileList is
683 * non-NULL, only the files in the list will be extracted from the
684 * cab file, otherwise all files will be extracted. Any number of
685 * spaces, tabs, or colons can be before or after the list, but
686 * the list itself must only be separated by colons.
688 HRESULT WINAPI ExtractFilesA(LPCSTR CabName, LPCSTR ExpandDir, DWORD Flags,
689 LPCSTR FileList, LPVOID LReserved, DWORD Reserved)
694 DWORD dwFileCount = 0;
695 DWORD dwFilesFound = 0;
696 LPSTR szConvertedList = NULL;
698 TRACE("(%s, %s, %d, %s, %p, %d)\n", debugstr_a(CabName), debugstr_a(ExpandDir),
699 Flags, debugstr_a(FileList), LReserved, Reserved);
701 if (!CabName || !ExpandDir)
704 if (GetFileAttributesA(ExpandDir) == INVALID_FILE_ATTRIBUTES)
705 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
707 hCabinet = LoadLibraryA("cabinet.dll");
711 ZeroMemory(&session, sizeof(SESSION));
713 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
720 lstrcpyA(session.Destination, ExpandDir);
724 szConvertedList = convert_file_list(FileList, &dwFileCount);
725 if (!szConvertedList)
731 dwFilesFound = fill_file_list(&session, CabName, szConvertedList);
732 if (dwFilesFound != dwFileCount)
739 session.Operation |= EXTRACT_FILLFILELIST;
741 session.Operation |= EXTRACT_EXTRACTFILES;
742 res = pExtract(&session, CabName);
745 free_file_list(&session);
746 FreeLibrary(hCabinet);
747 HeapFree(GetProcessHeap(), 0, szConvertedList);
752 /***********************************************************************
753 * ExtractFilesW (ADVPACK.@)
755 * Extracts the specified files from a cab archive into
756 * a destination directory.
759 * CabName [I] Filename of the cab archive.
760 * ExpandDir [I] Destination directory for the extracted files.
761 * Flags [I] Reserved.
762 * FileList [I] Optional list of files to extract. See NOTES.
763 * LReserved [I] Reserved. Must be NULL.
764 * Reserved [I] Reserved. Must be 0.
771 * FileList is a colon-separated list of filenames. If FileList is
772 * non-NULL, only the files in the list will be extracted from the
773 * cab file, otherwise all files will be extracted. Any number of
774 * spaces, tabs, or colons can be before or after the list, but
775 * the list itself must only be separated by colons.
780 HRESULT WINAPI ExtractFilesW(LPCWSTR CabName, LPCWSTR ExpandDir, DWORD Flags,
781 LPCWSTR FileList, LPVOID LReserved, DWORD Reserved)
783 char *cab_name = NULL, *expand_dir = NULL, *file_list = NULL;
786 TRACE("(%s, %s, %d, %s, %p, %d)\n", debugstr_w(CabName), debugstr_w(ExpandDir),
787 Flags, debugstr_w(FileList), LReserved, Reserved);
790 cab_name = heap_strdupWtoA(CabName);
792 return E_OUTOFMEMORY;
796 expand_dir = heap_strdupWtoA(ExpandDir);
798 hres = E_OUTOFMEMORY;
801 if(SUCCEEDED(hres) && FileList) {
802 file_list = heap_strdupWtoA(FileList);
804 hres = E_OUTOFMEMORY;
807 /* cabinet.dll, which does the real job of extracting files, doesn't have UNICODE API,
808 so we need W->A conversion at some point anyway. */
810 hres = ExtractFilesA(cab_name, expand_dir, Flags, file_list, LReserved, Reserved);
813 heap_free(expand_dir);
814 heap_free(file_list);
818 /***********************************************************************
819 * FileSaveMarkNotExistA (ADVPACK.@)
821 * See FileSaveMarkNotExistW.
823 HRESULT WINAPI FileSaveMarkNotExistA(LPSTR pszFileList, LPSTR pszDir, LPSTR pszBaseName)
825 TRACE("(%s, %s, %s)\n", debugstr_a(pszFileList),
826 debugstr_a(pszDir), debugstr_a(pszBaseName));
828 return AddDelBackupEntryA(pszFileList, pszDir, pszBaseName, AADBE_DEL_ENTRY);
831 /***********************************************************************
832 * FileSaveMarkNotExistW (ADVPACK.@)
834 * Marks the files in the file list as not existing so they won't be
835 * backed up during a save.
838 * pszFileList [I] NULL-separated list of filenames.
839 * pszDir [I] Path of the backup directory.
840 * pszBaseName [I] Basename of the INI file.
846 HRESULT WINAPI FileSaveMarkNotExistW(LPWSTR pszFileList, LPWSTR pszDir, LPWSTR pszBaseName)
848 TRACE("(%s, %s, %s)\n", debugstr_w(pszFileList),
849 debugstr_w(pszDir), debugstr_w(pszBaseName));
851 return AddDelBackupEntryW(pszFileList, pszDir, pszBaseName, AADBE_DEL_ENTRY);
854 /***********************************************************************
855 * FileSaveRestoreA (ADVPACK.@)
857 * See FileSaveRestoreW.
859 HRESULT WINAPI FileSaveRestoreA(HWND hDlg, LPSTR pszFileList, LPSTR pszDir,
860 LPSTR pszBaseName, DWORD dwFlags)
862 UNICODE_STRING filelist, dir, basename;
865 TRACE("(%p, %s, %s, %s, %d)\n", hDlg, debugstr_a(pszFileList),
866 debugstr_a(pszDir), debugstr_a(pszBaseName), dwFlags);
868 RtlCreateUnicodeStringFromAsciiz(&filelist, pszFileList);
869 RtlCreateUnicodeStringFromAsciiz(&dir, pszDir);
870 RtlCreateUnicodeStringFromAsciiz(&basename, pszBaseName);
872 hr = FileSaveRestoreW(hDlg, filelist.Buffer, dir.Buffer,
873 basename.Buffer, dwFlags);
875 RtlFreeUnicodeString(&filelist);
876 RtlFreeUnicodeString(&dir);
877 RtlFreeUnicodeString(&basename);
882 /***********************************************************************
883 * FileSaveRestoreW (ADVPACK.@)
885 * Saves or restores the files in the specified file list.
888 * hDlg [I] Handle to the dialog used for the display.
889 * pszFileList [I] NULL-separated list of filenames.
890 * pszDir [I] Path of the backup directory.
891 * pszBaseName [I] Basename of the backup files.
892 * dwFlags [I] See advpub.h.
899 * If pszFileList is NULL on restore, all files will be restored.
904 HRESULT WINAPI FileSaveRestoreW(HWND hDlg, LPWSTR pszFileList, LPWSTR pszDir,
905 LPWSTR pszBaseName, DWORD dwFlags)
907 FIXME("(%p, %s, %s, %s, %d) stub\n", hDlg, debugstr_w(pszFileList),
908 debugstr_w(pszDir), debugstr_w(pszBaseName), dwFlags);
913 /***********************************************************************
914 * FileSaveRestoreOnINFA (ADVPACK.@)
916 * See FileSaveRestoreOnINFW.
918 HRESULT WINAPI FileSaveRestoreOnINFA(HWND hWnd, LPCSTR pszTitle, LPCSTR pszINF,
919 LPCSTR pszSection, LPCSTR pszBackupDir,
920 LPCSTR pszBaseBackupFile, DWORD dwFlags)
922 UNICODE_STRING title, inf, section;
923 UNICODE_STRING backupdir, backupfile;
926 TRACE("(%p, %s, %s, %s, %s, %s, %d)\n", hWnd, debugstr_a(pszTitle),
927 debugstr_a(pszINF), debugstr_a(pszSection), debugstr_a(pszBackupDir),
928 debugstr_a(pszBaseBackupFile), dwFlags);
930 RtlCreateUnicodeStringFromAsciiz(&title, pszTitle);
931 RtlCreateUnicodeStringFromAsciiz(&inf, pszINF);
932 RtlCreateUnicodeStringFromAsciiz(§ion, pszSection);
933 RtlCreateUnicodeStringFromAsciiz(&backupdir, pszBackupDir);
934 RtlCreateUnicodeStringFromAsciiz(&backupfile, pszBaseBackupFile);
936 hr = FileSaveRestoreOnINFW(hWnd, title.Buffer, inf.Buffer, section.Buffer,
937 backupdir.Buffer, backupfile.Buffer, dwFlags);
939 RtlFreeUnicodeString(&title);
940 RtlFreeUnicodeString(&inf);
941 RtlFreeUnicodeString(§ion);
942 RtlFreeUnicodeString(&backupdir);
943 RtlFreeUnicodeString(&backupfile);
948 /***********************************************************************
949 * FileSaveRestoreOnINFW (ADVPACK.@)
953 * hWnd [I] Handle to the window used for the display.
954 * pszTitle [I] Title of the window.
955 * pszINF [I] Fully-qualified INF filename.
956 * pszSection [I] GenInstall INF section name.
957 * pszBackupDir [I] Directory to store the backup file.
958 * pszBaseBackupFile [I] Basename of the backup files.
959 * dwFlags [I] See advpub.h
966 * If pszSection is NULL, the default section will be used.
971 HRESULT WINAPI FileSaveRestoreOnINFW(HWND hWnd, LPCWSTR pszTitle, LPCWSTR pszINF,
972 LPCWSTR pszSection, LPCWSTR pszBackupDir,
973 LPCWSTR pszBaseBackupFile, DWORD dwFlags)
975 FIXME("(%p, %s, %s, %s, %s, %s, %d): stub\n", hWnd, debugstr_w(pszTitle),
976 debugstr_w(pszINF), debugstr_w(pszSection), debugstr_w(pszBackupDir),
977 debugstr_w(pszBaseBackupFile), dwFlags);
982 /***********************************************************************
983 * GetVersionFromFileA (ADVPACK.@)
985 * See GetVersionFromFileExW.
987 HRESULT WINAPI GetVersionFromFileA(LPCSTR Filename, LPDWORD MajorVer,
988 LPDWORD MinorVer, BOOL Version )
990 TRACE("(%s, %p, %p, %d)\n", debugstr_a(Filename), MajorVer, MinorVer, Version);
991 return GetVersionFromFileExA(Filename, MajorVer, MinorVer, Version);
994 /***********************************************************************
995 * GetVersionFromFileW (ADVPACK.@)
997 * See GetVersionFromFileExW.
999 HRESULT WINAPI GetVersionFromFileW(LPCWSTR Filename, LPDWORD MajorVer,
1000 LPDWORD MinorVer, BOOL Version )
1002 TRACE("(%s, %p, %p, %d)\n", debugstr_w(Filename), MajorVer, MinorVer, Version);
1003 return GetVersionFromFileExW(Filename, MajorVer, MinorVer, Version);
1006 /* data for GetVersionFromFileEx */
1007 typedef struct tagLANGANDCODEPAGE
1013 /***********************************************************************
1014 * GetVersionFromFileExA (ADVPACK.@)
1016 * See GetVersionFromFileExW.
1018 HRESULT WINAPI GetVersionFromFileExA(LPCSTR lpszFilename, LPDWORD pdwMSVer,
1019 LPDWORD pdwLSVer, BOOL bVersion )
1021 UNICODE_STRING filename;
1024 TRACE("(%s, %p, %p, %d)\n", debugstr_a(lpszFilename),
1025 pdwMSVer, pdwLSVer, bVersion);
1027 RtlCreateUnicodeStringFromAsciiz(&filename, lpszFilename);
1029 res = GetVersionFromFileExW(filename.Buffer, pdwMSVer, pdwLSVer, bVersion);
1031 RtlFreeUnicodeString(&filename);
1036 /***********************************************************************
1037 * GetVersionFromFileExW (ADVPACK.@)
1039 * Gets the files version or language information.
1042 * lpszFilename [I] The file to get the info from.
1043 * pdwMSVer [O] Major version.
1044 * pdwLSVer [O] Minor version.
1045 * bVersion [I] Whether to retrieve version or language info.
1048 * Always returns S_OK.
1051 * If bVersion is TRUE, version information is retrieved, else
1052 * pdwMSVer gets the language ID and pdwLSVer gets the codepage ID.
1054 HRESULT WINAPI GetVersionFromFileExW(LPCWSTR lpszFilename, LPDWORD pdwMSVer,
1055 LPDWORD pdwLSVer, BOOL bVersion )
1057 VS_FIXEDFILEINFO *pFixedVersionInfo;
1058 LANGANDCODEPAGE *pLangAndCodePage;
1059 DWORD dwHandle, dwInfoSize;
1060 WCHAR szWinDir[MAX_PATH];
1061 WCHAR szFile[MAX_PATH];
1062 LPVOID pVersionInfo = NULL;
1063 BOOL bFileCopied = FALSE;
1066 static const WCHAR backslash[] = {'\\',0};
1067 static const WCHAR translation[] = {
1068 '\\','V','a','r','F','i','l','e','I','n','f','o',
1069 '\\','T','r','a','n','s','l','a','t','i','o','n',0
1072 TRACE("(%s, %p, %p, %d)\n", debugstr_w(lpszFilename),
1073 pdwMSVer, pdwLSVer, bVersion);
1078 lstrcpynW(szFile, lpszFilename, MAX_PATH);
1080 dwInfoSize = GetFileVersionInfoSizeW(szFile, &dwHandle);
1083 /* check that the file exists */
1084 if (GetFileAttributesW(szFile) == INVALID_FILE_ATTRIBUTES)
1087 /* file exists, but won't be found by GetFileVersionInfoSize,
1088 * so copy it to the temp dir where it will be found.
1090 GetWindowsDirectoryW(szWinDir, MAX_PATH);
1091 GetTempFileNameW(szWinDir, NULL, 0, szFile);
1092 CopyFileW(lpszFilename, szFile, FALSE);
1095 dwInfoSize = GetFileVersionInfoSizeW(szFile, &dwHandle);
1100 pVersionInfo = HeapAlloc(GetProcessHeap(), 0, dwInfoSize);
1104 if (!GetFileVersionInfoW(szFile, dwHandle, dwInfoSize, pVersionInfo))
1109 if (!VerQueryValueW(pVersionInfo, backslash,
1110 (LPVOID *)&pFixedVersionInfo, &uValueLen))
1116 *pdwMSVer = pFixedVersionInfo->dwFileVersionMS;
1117 *pdwLSVer = pFixedVersionInfo->dwFileVersionLS;
1121 if (!VerQueryValueW(pVersionInfo, translation,
1122 (LPVOID *)&pLangAndCodePage, &uValueLen))
1128 *pdwMSVer = pLangAndCodePage->wLanguage;
1129 *pdwLSVer = pLangAndCodePage->wCodePage;
1133 HeapFree(GetProcessHeap(), 0, pVersionInfo);
1136 DeleteFileW(szFile);