/*++ Copyright (c) 2001 Microsoft Corporation Module Name: Duinst.cpp Abstract: Contains the main installation code used by the app. Notes: Unicode only. History: 03/02/2001 rparsons Created --*/ #include "precomp.h" extern SETUP_INFO g_si; /*++ Routine Description: Determines if a newer version of our package exists on the target Arguments: None Return Value: TRUE if the installation should take place FALSE if the installation should not take place -1 on failure --*/ int InstallCheckVersion() { BOOL fReturn = FALSE; CRegistry creg; DWORDLONG dwlPackageVersion = 0; DWORDLONG dwlInstalledVersion = 0; char szActiveSetupKey[MAX_PATH] = ""; char szBuffer[MAX_PATH*3] = ""; WCHAR wszActiveSetupKey[MAX_PATH] = L""; WCHAR wszPackageVersion[MAX_PATH] = L""; LPWSTR lpwInstalledVersion = NULL; // // Get the registry key path from the INF // fReturn = SetupGetLineTextA(NULL, g_si.hInf, "Strings", "ActiveSetupKey", szActiveSetupKey, sizeof(szActiveSetupKey), NULL); if (!fReturn) { return -1; } pAnsiToUnicode(szActiveSetupKey, wszActiveSetupKey, MAX_PATH); // // Determine if a package is already installed // fReturn = creg.IsRegistryKeyPresent(HKEY_LOCAL_MACHINE, wszActiveSetupKey); if (!fReturn) { return TRUE; } // // A package is installed - determine the version // lpwInstalledVersion = creg.GetString(HKEY_LOCAL_MACHINE, wszActiveSetupKey, L"Version", TRUE); if (NULL == lpwInstalledVersion) { return -1; } // // Convert the installed version string to a number // VersionStringToNumber(lpwInstalledVersion, &dwlInstalledVersion); creg.Free(lpwInstalledVersion); // // Now scan the INF AddReg data to determine if a newer version // is present with our package // if (0 != dwlInstalledVersion) { INFCONTEXT InfContext; BOOL fRetVal = FALSE; fRetVal = SetupFindFirstLineA(g_si.hInf, INF_VERSION_INFO, NULL, &InfContext); while (fRetVal) { if ((SetupGetStringFieldA(&InfContext, 1, szBuffer, sizeof(szBuffer), NULL) == FALSE) || (_stricmp(szBuffer, "HKLM") != 0 )) { goto NextLine; } if ((SetupGetStringFieldA(&InfContext, 2, szBuffer, sizeof(szBuffer), NULL) == FALSE) || (_stricmp(szBuffer, szActiveSetupKey) != 0 )) { goto NextLine; } if ((SetupGetStringFieldA(&InfContext, 3, szBuffer, sizeof(szBuffer), NULL) == TRUE) && (_stricmp(szBuffer, "Version") == 0 )) { break; } NextLine: fRetVal = SetupFindNextLine(&InfContext, &InfContext); } if (fRetVal) { if (SetupGetStringFieldA(&InfContext, 5, szBuffer, sizeof(szBuffer), NULL) == TRUE) { pAnsiToUnicode(szBuffer, wszPackageVersion, MAX_PATH); VersionStringToNumber(wszPackageVersion, &dwlPackageVersion); g_si.dwlUpdateVersion = dwlPackageVersion; } } // // Compare the versions // if (dwlPackageVersion >= dwlInstalledVersion) { return TRUE; // Package has newer than what's installed } } return FALSE; } /*++ Routine Description: Installs catalog files, if there are any to install Arguments: hInf - Handle to the INF containing catalog names lpwSourcePath - The path where the file is currently located Return Value: TRUE on success, FALSE otherwise --*/ BOOL InstallCatalogFiles( IN HINF hInf, IN LPCWSTR lpwSourcePath ) { DWORD dwTargetCatVersion = 0; DWORD dwSourceCatVersion = 0; DWORD dwError = 0; BOOL fReturn = FALSE; char szCatFileName[MAX_PATH] = ""; WCHAR wszCatFileName[MAX_PATH] = L""; WCHAR wszTargetCat[MAX_PATH] = L""; char szSourceCat[MAX_PATH] = ""; WCHAR wszSourceCat[MAX_PATH] = L""; char szTempCat[MAX_PATH] = ""; WCHAR wszTempCat[MAX_PATH] = L""; INFCONTEXT InfContext; WCHAR wszCatRoot[] = L"CatRoot\\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}"; // // Loop through all the lines in the CatalogsToInstall section, // verifying and installing each one // fReturn = SetupFindFirstLineA(hInf, INF_CAT_SECTION_NAME, NULL, &InfContext) && SetupGetLineTextA(&InfContext, NULL, NULL, NULL, szCatFileName, MAX_PATH, NULL); while (fReturn) { pAnsiToUnicode(szCatFileName, wszCatFileName, MAX_PATH); // // Get paths to src and dest, compare versions, // and do the copy if necessary // wsprintf(wszSourceCat, L"%s\\%s", g_si.lpwExtractPath, wszCatFileName); wsprintf(wszTargetCat, L"%s\\%s\\%s", g_si.lpwSystem32Directory, wszCatRoot, wszCatFileName); wsprintf(wszTempCat, L"%s\\%s", g_si.lpwWindowsDirectory, wszCatFileName); dwTargetCatVersion = GetCatVersion(wszTargetCat); dwSourceCatVersion = GetCatVersion(wszSourceCat); if (dwTargetCatVersion > dwSourceCatVersion) { // If the SP?.CAT on the target is greater than ours // don't install ours Print(TRACE, L"[InstallCatalogFiles] Not installing older catalog\n"); return TRUE; } pUnicodeToAnsi(wszSourceCat, szSourceCat, MAX_PATH); pUnicodeToAnsi(wszTempCat, szTempCat, MAX_PATH); // // Put the CAT file in the Windows directory // dwError = SetupDecompressOrCopyFileA(szSourceCat, szTempCat, NULL); if (NO_ERROR == dwError) { // // Perform the installation using the approriate function // dwError = pInstallCatalogFile(wszTempCat, wszCatFileName); if (NO_ERROR != dwError) { Print(ERROR, L"[InstallCatalogFiles] Failed to install catalog %s\n", wszTempCat); return FALSE; } } DeleteFile(wszTempCat); // clean up copied-over file fReturn = SetupFindNextLine(&InfContext, &InfContext) && SetupGetLineTextA(&InfContext, NULL, NULL, NULL, szCatFileName, MAX_PATH, NULL); } return TRUE; } /*++ Routine Description: Creates the uninstall key in the registry Arguments: None Return Value: TRUE on success, FALSE otherwise --*/ BOOL InstallWriteUninstallKey() { BOOL fReturn = FALSE; CRegistry creg; char szUninstallKey[MAX_PATH] = ""; WCHAR wszUninstallKey[MAX_PATH] = L""; WCHAR wszUninstallCommand[MAX_PATH] = L""; HKEY hKey = NULL; // // Get the path for the uninstall key from the INF // fReturn = SetupGetLineTextA(NULL, g_si.hInf, "Strings", "UninstallKey", szUninstallKey, sizeof(szUninstallKey), NULL); if (!fReturn) { return FALSE; } pAnsiToUnicode(szUninstallKey, wszUninstallKey, MAX_PATH); // // Attempt to create the key or open if it already exists // hKey = creg.CreateKey(HKEY_LOCAL_MACHINE, wszUninstallKey, KEY_SET_VALUE); if (NULL == hKey) { Print(ERROR, L"[InstallWriteUninstallKey] Failed to create key\n"); return FALSE; } // // Set the DisplayName // fReturn = creg.SetString(hKey, NULL, REG_DISPLAY_NAME, g_si.lpwPrettyAppName, FALSE); if (!fReturn) { Print(ERROR, L"[InstallWriteUninstallKey] Failed to set DisplayName\n"); return FALSE; } // // Build the uninstall string // wsprintf(wszUninstallCommand, L"%s\\%s.exe %s", g_si.lpwInstallDirectory, g_si.lpwEventLogSourceName, UNINSTALL_SWITCH); // // Set the Uninstall string // fReturn = creg.SetString(HKEY_LOCAL_MACHINE, wszUninstallKey, REG_UNINSTALL_STRING, wszUninstallCommand, TRUE); if (!fReturn) { Print(ERROR, L"[InstallWriteUninstallKey] Failed to set UninstallString\n"); return FALSE; } return TRUE; } /*++ Routine Description: Run any EXEs specified in the INF file Arguments: None Return Value: TRUE on success, FALSE otherwise --*/ BOOL InstallRunINFProcesses() { char szFileName[MAX_PATH] = ""; WCHAR wszExpFileName[MAX_PATH] = L""; WCHAR wszFileName[MAX_PATH] = L""; BOOL fReturn = FALSE; INFCONTEXT InfContext; // // Loop through all the lines in the ProcessesToRun section, // spawning off each one // fReturn = SetupFindFirstLineA(g_si.hInf, INF_PROCESSES_TO_RUN, NULL, &InfContext) && SetupGetLineTextA(&InfContext, NULL, NULL, NULL, szFileName, MAX_PATH, NULL); while (fReturn) { pAnsiToUnicode(szFileName, wszFileName, MAX_PATH); // // Spawn the EXE and ignore any errors returned // ExpandEnvironmentStrings(wszFileName, wszExpFileName, MAX_PATH); LaunchProcessAndWait(wszExpFileName, NULL); fReturn = SetupFindNextLine(&InfContext, &InfContext) && SetupGetLineTextA(&InfContext, NULL, NULL, NULL, szFileName, MAX_PATH, NULL); } return TRUE; } /*++ Routine Description: Sets up the specified directory for use Arguments: lpwDirectoryPath - Full path to the directory Return Value: TRUE on success, FALSE otherwise --*/ BOOL InstallPrepareDirectory( IN LPWSTR lpwDirectoryPath, IN DWORD dwAttributes ) { BOOL fReturn = FALSE; LPWSTR lpwParentPath = NULL, lpwEnd = NULL; // // See if the directory exists // if (GetFileAttributes(lpwDirectoryPath) == -1) { // // Didn't exist - attempt to create the directory // if (!CreateDirectory(lpwDirectoryPath, NULL)) { Print(ERROR, L"[InstallPrepareDirectory] Failed to create directory %s\n", lpwDirectoryPath); return FALSE; } } // // Build a path to the parent based on it's child // lpwParentPath = (LPWSTR) MALLOC((wcslen(lpwDirectoryPath)+1)*sizeof(WCHAR)); if (NULL == lpwParentPath) { return FALSE; } wcscpy(lpwParentPath, lpwDirectoryPath); lpwEnd = wcsrchr(lpwParentPath, '\\'); if (lpwEnd) { *lpwEnd = 0; } // // Adjust the permissions on the new directory // to match the parent // fReturn = MirrorDirectoryPerms(lpwParentPath, lpwDirectoryPath); if (!fReturn) { Print(ERROR, L"[InstallPrepareDirectory] Failed to mirror permissions from %s to %s\n", lpwParentPath, lpwDirectoryPath); return FALSE; } SetFileAttributes(lpwDirectoryPath, dwAttributes); return TRUE; } /*++ Routine Description: Performs the backup of files that get replaced during install Arguments: None Return Value: TRUE on success, FALSE otherwise --*/ BOOL InstallBackupFiles() { WCHAR wszBackupDir[MAX_PATH] = L""; WCHAR wszSourceFileName[MAX_PATH] = L""; WCHAR wszBackupFileName[MAX_PATH] = L""; char szEntry[MAX_PATH] = ""; WCHAR wszEntry[MAX_PATH] = L""; char szFileName[MAX_PATH] = ""; WCHAR wszFileName[MAX_PATH] = L""; WCHAR wszRestoreSection[MAX_PATH] = L""; WCHAR wszKey[10] = L""; BOOL fReturn = FALSE, fResult = FALSE; LPWSTR lpwDestDir = NULL; UINT uCount = 0; INFCONTEXT InfContext; // // Remove any previous backup directories // Don't check the return as it's not critical // that this happen successfully // wsprintf(wszBackupDir, L"%s\\Backup", g_si.lpwInstallDirectory); CommonRemoveDirectoryAndFiles(wszBackupDir, (PVOID) FALSE, FALSE, FALSE); wszBackupDir[0] = 0; wsprintf(wszBackupDir, L"%s\\%s", g_si.lpwInstallDirectory, g_si.lpwUninstallDirectory); CommonRemoveDirectoryAndFiles(wszBackupDir, (PVOID) FALSE, FALSE, FALSE); // // Prepare the new backup directory // fReturn = InstallPrepareDirectory(wszBackupDir, FILE_ATTRIBUTE_HIDDEN); if (!fReturn) { return FALSE; } // // Step through each entry in the queue // while (g_si.BackupFileQueue.GetSize()) { g_si.BackupFileQueue.Dequeue(wszEntry, MAX_PATH - 1, FALSE); pUnicodeToAnsi(wszEntry, szEntry, MAX_PATH); // // Get the destination directory // GetNextToken(wszEntry, L"."); GetNextToken(NULL, L"."); lpwDestDir = GetNextToken(NULL, L"."); if (NULL == lpwDestDir) { return FALSE; } // // Loop through all the lines in the backup files section(s), // and perform the backup // fReturn = SetupFindFirstLineA(g_si.hInf, szEntry, NULL, &InfContext) && SetupGetLineTextA(&InfContext, NULL, NULL, NULL, szFileName, MAX_PATH, NULL); while (fReturn) { pAnsiToUnicode(szFileName, wszFileName, MAX_PATH); // // Build the path to the source file // wsprintf(wszSourceFileName, L"%s\\%s\\%s", g_si.lpwWindowsDirectory, lpwDestDir, wszFileName); // // Ensure that the source file exists // fResult = PathFileExists(wszSourceFileName); if (fResult) { // // Ensure that this file is not under WFP // fResult = IsFileProtected(wszSourceFileName); // // Build a path to the backup file // wsprintf(wszBackupFileName, L"%s\\%s", wszBackupDir, wszFileName); // // Backup the file - be sensitive to WFP // if (fResult) { fResult = ForceCopy(wszSourceFileName, wszBackupFileName); if (!fResult) { Print(ERROR, L"[InstallBackupFiles] Failed to copy %s to %s\n", wszSourceFileName, wszBackupFileName); return FALSE; } } else { fResult = ForceMove(wszSourceFileName, wszBackupFileName); if (!fResult) { Print(ERROR, L"[InstallBackupFiles] Failed to move %s to %s\n", wszSourceFileName, wszBackupFileName); return FALSE; } } // // Now save an entry to the INF // wsprintf(wszRestoreSection, L"Restore.Files.%s", lpwDestDir); wsprintf(wszKey, L"%u", ++uCount); SaveEntryToINF(wszRestoreSection, wszKey, wszFileName, g_si.lpwUninstallINFPath); } fReturn = SetupFindNextLine(&InfContext, &InfContext) && SetupGetLineTextA(&InfContext, NULL, NULL, NULL, szFileName, MAX_PATH, NULL); } } return TRUE; } /*++ Routine Description: Performs a backup of the specified registry keys during install Arguments: None Return Value: TRUE on success, FALSE otherwise --*/ BOOL InstallBackupRegistryKeys() { BOOL fReturn = FALSE, fResult = FALSE; HKEY hKeyRoot = NULL; char szEntry[MAX_PATH] = ""; WCHAR wszEntry[MAX_PATH] = L""; char szKeyPath[MAX_PATH*3] = ""; WCHAR wszKeyPath[MAX_PATH*3] = L""; WCHAR wszBackupFile[MAX_PATH] = L""; WCHAR wszKey[10] = L""; WCHAR wszEntryToSave[MAX_PATH*2] = L""; LPWSTR lpwKeyPart = NULL, lpwKeyRoot = NULL; UINT uCount = 0; CRegistry creg; INFCONTEXT InfContext; // // Step through each entry in the queue // while (g_si.BackupRegistryQueue.GetSize()) { g_si.BackupRegistryQueue.Dequeue(wszEntry, MAX_PATH - 1, FALSE); pUnicodeToAnsi(wszEntry, szEntry, MAX_PATH); // // Loop through all the lines in the backup registry section(s), // and perform the backup // fReturn = SetupFindFirstLineA(g_si.hInf, szEntry, NULL, &InfContext) && SetupGetLineTextA(&InfContext, NULL, NULL, NULL, szKeyPath, MAX_PATH, NULL); while (fReturn) { pAnsiToUnicode(szKeyPath, wszKeyPath, MAX_PATH*3); // // Split the key path into two separate parts // lpwKeyRoot = GetNextToken(wszKeyPath, L","); if (NULL == lpwKeyRoot) { break; } if (!_wcsicmp(lpwKeyRoot, L"HKLM")) { hKeyRoot = HKEY_LOCAL_MACHINE; } else if (!_wcsicmp(lpwKeyRoot, L"HKCR")) { hKeyRoot = HKEY_CLASSES_ROOT; } else if (!_wcsicmp(lpwKeyRoot, L"HKCU")) { hKeyRoot = HKEY_CURRENT_USER; } else if (!_wcsicmp(lpwKeyRoot, L"HKU")) { hKeyRoot = HKEY_USERS; } else { break; } lpwKeyPart = GetNextToken(NULL, L","); if (NULL == lpwKeyPart) { break; } // // Verify that the specified key exists // fResult = creg.IsRegistryKeyPresent(hKeyRoot, lpwKeyPart); if (fResult) { // // Build a path to the file for the backup // and backup the key // wsprintf(wszBackupFile, L"%s\\%s\\Regbkp%u", g_si.lpwInstallDirectory, g_si.lpwUninstallDirectory, ++uCount); fResult = creg.BackupRegistryKey(hKeyRoot, lpwKeyPart, wszBackupFile, TRUE); if (!fResult) { Print(ERROR, L"[InstallBackupRegistryKeys] Failed to backup key %s to %s\n", lpwKeyPart, wszBackupFile); return FALSE; } // // Now save an entry to the queue for the uninstall INF // We need one for deletion and restoration // wsprintf(wszEntryToSave, L"%s,%s", lpwKeyRoot, lpwKeyPart); wsprintf(wszKey, L"%u", ++uCount); SaveEntryToINF(INF_DELETE_REGISTRYW, wszKey, wszEntryToSave, g_si.lpwUninstallINFPath); wsprintf(wszEntryToSave, L"%s,%s,%s", lpwKeyRoot, lpwKeyPart, wszBackupFile); SaveEntryToINF(INF_RESTORE_REGISTRYW, wszKey, wszEntryToSave, g_si.lpwUninstallINFPath); } fReturn = SetupFindNextLine(&InfContext, &InfContext) && SetupGetLineTextA(&InfContext, NULL, NULL, NULL, szKeyPath, MAX_PATH, NULL); } } return TRUE; } /*++ Routine Description: Performs the file copy operations Arguments: None Return Value: TRUE on success, FALSE otherwise --*/ BOOL InstallCopyFiles() { WCHAR wszBackupDir[MAX_PATH] = L""; WCHAR wszDestFileName[MAX_PATH] = L""; WCHAR wszSourceFileName[MAX_PATH] = L""; char szEntry[MAX_PATH] = ""; WCHAR wszEntry[MAX_PATH] = L""; char szFileName[MAX_PATH] = ""; WCHAR wszFileName[MAX_PATH] = L""; BOOL fReturn = FALSE, fResult = FALSE; LPWSTR lpwDestDir = NULL; DWORDLONG dwlSourceVersion = 0, dwlDestVersion = 0; INFCONTEXT InfContext; // // Step through each entry in the queue // while (g_si.CopyFileQueue.GetSize()) { g_si.CopyFileQueue.Dequeue(wszEntry, MAX_PATH - 1, FALSE); pUnicodeToAnsi(wszEntry, szEntry, MAX_PATH); // // Get the destination directory // GetNextToken(wszEntry, L"."); GetNextToken(NULL, L"."); lpwDestDir = GetNextToken(NULL, L"."); if (NULL == lpwDestDir) { break; } // // Loop through all the lines in the copy files section(s), // and perform the copy // fReturn = SetupFindFirstLineA(g_si.hInf, szEntry, NULL, &InfContext) && SetupGetLineTextA(&InfContext, NULL, NULL, NULL, szFileName, MAX_PATH, NULL); while (fReturn) { pAnsiToUnicode(szFileName, wszFileName, MAX_PATH); // // Build the path to the destination file // wsprintf(wszDestFileName, L"%s\\%s\\%s", g_si.lpwWindowsDirectory, lpwDestDir, wszFileName); // // Build the path to the source file // wsprintf(wszSourceFileName, L"%s\\%s", g_si.lpwExtractPath, wszFileName); // // Get version information from the source and destination // if (!GetVersionInfoFromImage(wszSourceFileName, &dwlSourceVersion)) { Print(TRACE, L"[InstallCopyFiles] Failed to get version info from %s\n", wszSourceFileName); dwlSourceVersion = 0; } if (!GetVersionInfoFromImage(wszDestFileName, &dwlDestVersion)) { Print(TRACE, L"[InstallCopyFiles] Failed to get version info from %s\n", wszDestFileName); dwlDestVersion = 0; } // // If neither file had version information, perform the copy. // If the target version is less than the source version, // perform the copy. // Otherwise, move to the next file // if ((dwlSourceVersion == 0 && dwlDestVersion == 0) || (dwlDestVersion <= dwlSourceVersion)) { // // Ensure that this file is not under WFP // fResult = IsFileProtected(wszDestFileName); // // Copy the file - be sensitive to WFP // if (fResult) { Print(TRACE, L"[InstallCopyFiles] Preparing to install WFP file from %s to %s\n", wszSourceFileName, wszDestFileName); fResult = CommonEnableProtectedRenames(); if (!fResult) { return FALSE; } fResult = InstallWFPFile(wszSourceFileName, wszFileName, wszDestFileName, g_si.fUpdateDllCache); if (!fResult) { return FALSE; } } else { Print(TRACE, L"[InstallCopyFiles] Preparing to install file from %s to %s\n", wszSourceFileName, wszDestFileName); fResult = ForceCopy(wszSourceFileName, wszDestFileName); if (!fResult) { Print(ERROR, L"[InstallCopyFiles] Failed to install file from %s to %s\n", wszSourceFileName, wszDestFileName); return FALSE; } } } else { break; } fReturn = SetupFindNextLine(&InfContext, &InfContext) && SetupGetLineTextA(&InfContext, NULL, NULL, NULL, szFileName, MAX_PATH, NULL); } } return TRUE; } /*++ Routine Description: Installs a file that is protected by WFP Arguments: lpwSourceFileName - Path to the source file lpwDestFileName - Name of the destination file lpwDestFileNamePath - Name & path to the destination file fUpdateDllCache - A flag to indicate if the file should be placed in the DllCache directory Return Value: TRUE on success, FALSE otherwise --*/ BOOL InstallWFPFile( IN LPCWSTR lpwSourceFileName, IN LPCWSTR lpwDestFileName, IN LPCWSTR lpwDestFileNamePath, IN BOOL fUpdateDllCache ) { LPWSTR lpwCachePath = NULL; LPWSTR lpwExpandedCachePath = NULL; LPWSTR lpwTempFileName = NULL; DWORD cbSize = 0; WCHAR wszDllCachePath[MAX_PATH] = L""; WCHAR wszExtraFilePath[MAX_PATH] = L""; WCHAR wszExtraFileName[MAX_PATH] = L""; WCHAR wszOldSourcesPath[MAX_PATH] = L""; CRegistry creg; BOOL fAddedToReg = FALSE, fReturn = FALSE; if (fUpdateDllCache) { // // Try to get the dllcache directory path from // the registry // lpwCachePath = creg.GetString(HKEY_LOCAL_MACHINE, REG_WINFP_PATH, L"SfcDllCacheDir", TRUE); if (lpwCachePath) { if (cbSize = ExpandEnvironmentStrings(lpwCachePath, lpwExpandedCachePath, 0)) { lpwExpandedCachePath = (LPWSTR) MALLOC(cbSize*sizeof(WCHAR)); if (lpwExpandedCachePath) { if (ExpandEnvironmentStrings(lpwCachePath, lpwExpandedCachePath, cbSize)) { // // Build a full path to \%windir%\system32\dllcache\filename.xxx // wsprintf(wszDllCachePath, L"%s\\%s", lpwExpandedCachePath, lpwDestFileName); } } } } // // If we couldn't get it from that key, try another // if (NULL == lpwExpandedCachePath) { lpwCachePath = creg.GetString(HKEY_LOCAL_MACHINE, REG_WINLOGON_PATH, L"SfcDllCacheDir", TRUE); if (lpwCachePath) { if (cbSize = ExpandEnvironmentStrings(lpwCachePath, lpwExpandedCachePath, 0)) { lpwExpandedCachePath = (LPWSTR) MALLOC(cbSize*sizeof(WCHAR)); if (lpwExpandedCachePath) { if (ExpandEnvironmentStrings(lpwCachePath, lpwExpandedCachePath, cbSize)) { // // Build a full path to \%windir%\system32\dllcache\filename.xxx // wsprintf(wszDllCachePath, L"%s\\%s", lpwExpandedCachePath, lpwDestFileName); } } } } } // // If neither key worked, build the path manually // if (NULL == lpwExpandedCachePath) { wsprintf(wszDllCachePath, L"%s\\DllCache\\%s", g_si.lpwSystem32Directory, lpwDestFileName); } // // Replace the file in the DllCache directory // if (!CopyFile(lpwSourceFileName, wszDllCachePath, FALSE)) { Print(ERROR, L"[InstallWFPFile] Failed to copy %s to %s\n", lpwSourceFileName, wszDllCachePath); goto cleanup; return FALSE; } } // // Put an additional copy in 'Sources' under the install dir // The return is not critical for this operation // wsprintf(wszExtraFilePath, L"%s\\$Sources$", g_si.lpwInstallDirectory); wsprintf(wszOldSourcesPath, L"%s\\Sources", g_si.lpwInstallDirectory); CommonRemoveDirectoryAndFiles(wszExtraFilePath, (PVOID) FALSE, FALSE, FALSE); InstallPrepareDirectory(wszExtraFilePath, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); wcscpy(wszExtraFileName, wszExtraFilePath); wcscat(wszExtraFileName, L"\\"); wcscat(wszExtraFileName, lpwDestFileName); if (!CopyFile(lpwSourceFileName, wszExtraFileName, FALSE)) { Print(ERROR, L"[InstallWFPFile] Failed to copy %s to %s\n", lpwSourceFileName, wszExtraFileName); } if (!g_si.fSourceDirAdded) { // // Remove any old source path that may exist // creg.RemoveStringFromMultiSz(HKEY_LOCAL_MACHINE, REG_INSTALL_SOURCES, L"Installation Sources", wszOldSourcesPath, TRUE); creg.RemoveStringFromMultiSz(HKEY_LOCAL_MACHINE, REG_INSTALL_SOURCES, L"Installation Sources", wszExtraFilePath, TRUE); fReturn = creg.AddStringToMultiSz(HKEY_LOCAL_MACHINE, REG_INSTALL_SOURCES, L"Installation Sources", wszExtraFilePath, TRUE); if (!fReturn) { Print(ERROR, L"[InstallWFPFile] Failed to add %s to registry\n", wszExtraFilePath); } g_si.fSourceDirAdded = TRUE; } // // The catalog file won't vouch for WFP files until // the next reboot. Put the file down and let the // Session Manager rename them // lpwTempFileName = CopyTempFile(lpwSourceFileName, g_si.lpwSystem32Directory); if (NULL == lpwTempFileName) { Print(ERROR, L"[InstallWFPFile] Failed to get temp file\n"); goto cleanup; return FALSE; } if (!MoveFileEx(lpwTempFileName, lpwDestFileNamePath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT)) { Print(ERROR, L"[InstallWFPFile] Failed to delay replace from %s to %s\n", lpwTempFileName, lpwDestFileNamePath); goto cleanup; return FALSE; } cleanup: if (lpwTempFileName) { FREE(lpwTempFileName); } if (lpwExpandedCachePath) { FREE(lpwExpandedCachePath); } return TRUE; } /*++ Routine Description: Retrieves the section names from the installation INF file. This dictates what operations will be performed during install Arguments: None Return Value: TRUE on success, FALSE otherwise --*/ BOOL InstallGetSectionsFromINF() { BOOL fReturn = FALSE; DWORD dwType = 0; char szSectionName[MAX_QUEUE_SIZE] = ""; char *pSectionName; WCHAR wszDirective[MAX_PATH] = L""; INFCONTEXT InfContext; // // Loop through all the lines in the Sections section(s), // fReturn = SetupFindFirstLineA(g_si.hInf, INF_MASTER_SECTIONS, NULL, &InfContext) && SetupGetLineTextA(&InfContext, NULL, NULL, NULL, szSectionName, MAX_QUEUE_SIZE, NULL); while (fReturn) { // // Determine which section we're working with // if (strstr(szSectionName, INF_BACKUP_FILES)) { dwType = dwBackupFiles; } else if (strstr(szSectionName, INF_BACKUP_REGISTRY)) { dwType = dwBackupRegistry; } else if (strstr(szSectionName, INF_DELETE_REGISTRY)) { dwType = dwDeleteRegistry; } else if (strstr(szSectionName, INF_COPY_FILES)) { dwType = dwCopyFiles; } else if (strstr(szSectionName, INF_REGISTRATIONS)) { dwType = dwRegistrations; } else if (strstr(szSectionName, INF_EXCLUDE)) { dwType = dwExclusionsInstall; } else if (strstr(szSectionName, INF_ADD_REGISTRY)) { dwType = dwAddRegistry; } else { Print(ERROR, L"[InstallGetSectionsFromINF] Illegal section name passed %s\n", szSectionName); return FALSE; // illegal section name } pSectionName = strtok(szSectionName, ","); do { pAnsiToUnicode(pSectionName, wszDirective, MAX_PATH); // // Loop through each section name and add it to the // appropriate queue // switch (dwType) { case dwBackupFiles: g_si.BackupFileQueue.Enqueue(wszDirective); break; case dwBackupRegistry: g_si.BackupRegistryQueue.Enqueue(wszDirective); break; case dwDeleteRegistry: g_si.DeleteRegistryQueue.Enqueue(wszDirective); break; case dwCopyFiles: g_si.CopyFileQueue.Enqueue(wszDirective); break; case dwRegistrations: g_si.RegistrationQueue.Enqueue(wszDirective); break; case dwExclusionsInstall: g_si.ExclusionQueue.Enqueue(wszDirective); break; case dwAddRegistry: g_si.AddRegistryQueue.Enqueue(wszDirective); break; default: return FALSE; // illegal section name } pSectionName = strtok(NULL, ","); } while (NULL != pSectionName); fReturn = SetupFindNextLine(&InfContext, &InfContext) && SetupGetLineTextA(&InfContext, NULL, NULL, NULL, szSectionName, MAX_QUEUE_SIZE, NULL); } return TRUE; } /*++ Routine Description: Merges the registry data from the INF into the registry Arguments: None Return Value: TRUE on success, FALSE otherwise --*/ BOOL InstallRegistryData() { BOOL fReturn = FALSE; char szEntry[MAX_PATH] = ""; WCHAR wszEntry[MAX_PATH] = L""; // // Step through each entry in the queue // while (g_si.AddRegistryQueue.GetSize()) { g_si.AddRegistryQueue.Dequeue(wszEntry, MAX_PATH - 1, FALSE); pUnicodeToAnsi(wszEntry, szEntry, MAX_PATH); // // Merge all the registry data from the INF // fReturn = SetupInstallFromInfSectionA(NULL, g_si.hInf, szEntry, SPINST_REGISTRY, NULL, NULL, 0, NULL, NULL, NULL, NULL); if (!fReturn) { Print(ERROR, L"[InstallRegistryData] Failed to merge registry data\n"); return FALSE; } } return TRUE; }