/******************************************************************** SetPropertyWellKnownSID Set a property with the localized name of a well known windows SID ********************************************************************/ static HRESULT SetPropertyWellKnownSID( __in WELL_KNOWN_SID_TYPE sidType, __in LPCWSTR wzPropertyName, __in BOOL fIncludeDomainName ) { HRESULT hr = S_OK; PSID psid = NULL; WCHAR wzRefDomain[MAX_PATH] = {0}; SID_NAME_USE nameUse; DWORD refSize = MAX_PATH; WCHAR wzName[MAX_PATH] = {0}; LPWSTR pwzPropertyValue = NULL; DWORD size = MAX_PATH; hr = AclGetWellKnownSid(sidType, &psid); ExitOnFailure1(hr, "Failed to get SID; skipping account %ls", wzPropertyName); if (!::LookupAccountSidW(NULL, psid, wzName, &size, wzRefDomain, &refSize, &nameUse)) { ExitWithLastError1(hr, "Failed to look up account for SID; skipping account %ls.", wzPropertyName); } if (fIncludeDomainName) { hr = StrAllocFormatted(&pwzPropertyValue, L"%s\\%s", wzRefDomain, wzName); ExitOnFailure(hr, "Failed to format property value"); hr = WcaSetProperty(wzPropertyName, pwzPropertyValue); ExitOnFailure(hr, "Failed write domain\\name property"); } else { hr = WcaSetProperty(wzPropertyName, wzName); ExitOnFailure(hr, "Failed write name-only property"); } LExit: if (NULL != psid) { ::LocalFree(psid); } ReleaseStr(pwzPropertyValue); return hr; }
/* Check for if directory is empty during install, sets "<PROPERTY>_NOT_EMPTY" otherise */ extern "C" UINT __stdcall CheckDirectoryEmpty(MSIHANDLE hInstall, const wchar_t *PropertyName) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; hr = WcaInitialize(hInstall, __FUNCTION__); ExitOnFailure(hr, "Failed to initialize"); WcaLog(LOGMSG_STANDARD, "Initialized."); wchar_t buf[MAX_PATH]; DWORD len = MAX_PATH; MsiGetPropertyW(hInstall, PropertyName, buf, &len); wcscat_s(buf, MAX_PATH, L"*.*"); WcaLog(LOGMSG_STANDARD, "Checking files in %S", buf); WIN32_FIND_DATAW data; HANDLE h; bool empty; h= FindFirstFile(buf, &data); if (h != INVALID_HANDLE_VALUE) { empty= true; for(;;) { if (wcscmp(data.cFileName, L".") || wcscmp(data.cFileName, L"..")) { empty= false; break; } if (!FindNextFile(h, &data)) break; } FindClose(h); } else { /* Non-existent directory, we handle it as empty */ empty = true; } if(empty) WcaLog(LOGMSG_STANDARD, "Directory %S is empty or non-existent", PropertyName); else WcaLog(LOGMSG_STANDARD, "Directory %S is NOT empty", PropertyName); wcscpy_s(buf, MAX_PATH, PropertyName); wcscat_s(buf, L"NOTEMPTY"); WcaSetProperty(buf, empty? L"":L"1"); LExit: return WcaFinalize(er); }
HRESULT BuildCommandLine( __in LPCWSTR wzProperty, __out LPWSTR *ppwzCommand ) { Assert(ppwzCommand); HRESULT hr = S_OK; BOOL fScheduled = ::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_SCHEDULED); BOOL fRollback = ::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_ROLLBACK); BOOL fCommit = ::MsiGetMode(WcaGetInstallHandle(), MSIRUNMODE_COMMIT); if (fScheduled || fRollback || fCommit) { if (WcaIsPropertySet("CustomActionData")) { hr = WcaGetProperty( L"CustomActionData", ppwzCommand); ExitOnFailure(hr, "Failed to get CustomActionData"); } } else if (WcaIsUnicodePropertySet(wzProperty)) { hr = WcaGetFormattedProperty(wzProperty, ppwzCommand); ExitOnFailure(hr, "Failed to get %ls", wzProperty); hr = WcaSetProperty(wzProperty, L""); // clear out the property now that we've read it ExitOnFailure(hr, "Failed to set %ls", wzProperty); } if (!*ppwzCommand) { ExitOnFailure(hr = E_INVALIDARG, "Failed to get command line data"); } if (L'"' != **ppwzCommand) { WcaLog(LOGMSG_STANDARD, "Command string must begin with quoted application name."); ExitOnFailure(hr = E_INVALIDARG, "invalid command line property value"); } LExit: return hr; }
/****************************************************************** WixSchedInternetShortcuts - entry point ********************************************************************/ extern "C" UINT __stdcall WixSchedInternetShortcuts( __in MSIHANDLE hInstall ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; UINT uiCost = 0; PMSIHANDLE hView = NULL; PMSIHANDLE hRec = NULL; MSIHANDLE hCreateFolderTable = NULL; MSIHANDLE hCreateFolderColumns = NULL; LPWSTR pwzCustomActionData = NULL; LPWSTR pwzComponent = NULL; LPWSTR pwzDirectory = NULL; LPWSTR pwzFilename = NULL; LPWSTR pwzTarget = NULL; LPWSTR pwzShortcutPath = NULL; int iAttr = 0; LPWSTR pwzIconFile = NULL; int iIconIndex = 0; IUniformResourceLocatorW* piURL = NULL; IShellLinkW* piShellLink = NULL; BOOL fInitializedCom = FALSE; hr = WcaInitialize(hInstall, "WixSchedInternetShortcuts"); ExitOnFailure(hr, "failed to initialize WixSchedInternetShortcuts."); // anything to do? if (S_OK != WcaTableExists(L"WixInternetShortcut")) { WcaLog(LOGMSG_STANDARD, "WixInternetShortcut table doesn't exist, so there are no Internet shortcuts to process"); goto LExit; } // check to see if we can create a shortcut - Server Core and others may not have a shell registered. hr = ::CoInitialize(NULL); ExitOnFailure(hr, "failed to initialize COM"); fInitializedCom = TRUE; hr = ::CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_ALL, IID_IUniformResourceLocatorW, (void**)&piURL); if (S_OK != hr) { WcaLog(LOGMSG_STANDARD, "failed to create an instance of IUniformResourceLocatorW, skipping shortcut creation"); ExitFunction1(hr = S_OK); } hr = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLinkW, (void**)&piShellLink); if (S_OK != hr) { WcaLog(LOGMSG_STANDARD, "failed to create an instance of IShellLinkW, skipping shortcut creation"); ExitFunction1(hr = S_OK); } // query and loop through all the shortcuts hr = WcaOpenExecuteView(vcsShortcutsQuery, &hView); ExitOnFailure(hr, "failed to open view on WixInternetShortcut table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { // read column values hr = WcaGetRecordString(hRec, esqComponent, &pwzComponent); ExitOnFailure(hr, "failed to get shortcut component"); hr = WcaGetRecordString(hRec, esqDirectory, &pwzDirectory); ExitOnFailure(hr, "failed to get shortcut directory"); hr = WcaGetRecordString(hRec, esqFilename, &pwzFilename); ExitOnFailure(hr, "failed to get shortcut filename"); hr = WcaGetRecordFormattedString(hRec, esqTarget, &pwzTarget); ExitOnFailure(hr, "failed to get shortcut target"); hr = WcaGetRecordInteger(hRec, esqAttributes, &iAttr); ExitOnFailure(hr, "failed to get shortcut attributes"); hr = WcaGetRecordFormattedString(hRec, esqIconFile, &pwzIconFile); ExitOnFailure(hr, "failed to get shortcut icon file"); hr = WcaGetRecordInteger(hRec, esqIconIndex, &iIconIndex); ExitOnFailure(hr, "failed to get shortcut icon index"); // skip processing this WixInternetShortcut row if the component isn't being configured WCA_TODO todo = WcaGetComponentToDo(pwzComponent); if (WCA_TODO_UNKNOWN == todo) { WcaLog(LOGMSG_VERBOSE, "Skipping shortcut for null-action component '%ls'", pwzComponent); continue; } // we need to create the directory where the shortcut is supposed to live; rather // than doing so in our deferred custom action, use the CreateFolder table to have MSI // make (and remove) them on our behalf (including the correct cleanup of parent directories). MSIDBERROR dbError = MSIDBERROR_NOERROR; WcaLog(LOGMSG_STANDARD, "Adding folder '%ls', component '%ls' to the CreateFolder table", pwzDirectory, pwzComponent); hr = WcaAddTempRecord(&hCreateFolderTable, &hCreateFolderColumns, L"CreateFolder", &dbError, 0, 2, pwzDirectory, pwzComponent); if (MSIDBERROR_DUPLICATEKEY == dbError) { WcaLog(LOGMSG_STANDARD, "Folder '%ls' already exists in the CreateFolder table; the above error is harmless", pwzDirectory); hr = S_OK; } ExitOnFailure(hr, "Couldn't add temporary CreateFolder row"); // only if we're installing/reinstalling do we need to schedule the deferred CA // (uninstallation is handled via permanent RemoveFile rows and temporary CreateFolder rows) if (WCA_TODO_INSTALL == todo || WCA_TODO_REINSTALL == todo) { // turn the Directory_ id into a path hr = WcaGetTargetPath(pwzDirectory, &pwzShortcutPath); ExitOnFailure(hr, "failed to allocate string for shortcut directory"); // append the shortcut filename hr = StrAllocConcat(&pwzShortcutPath, pwzFilename, 0); ExitOnFailure(hr, "failed to allocate string for shortcut filename"); // write the shortcut path and target to custom action data for deferred CAs hr = WcaWriteStringToCaData(pwzShortcutPath, &pwzCustomActionData); ExitOnFailure(hr, "failed to write shortcut path to custom action data"); hr = WcaWriteStringToCaData(pwzTarget, &pwzCustomActionData); ExitOnFailure(hr, "failed to write shortcut target to custom action data"); hr = WcaWriteIntegerToCaData(iAttr, &pwzCustomActionData); ExitOnFailure(hr, "failed to write shortcut attributes to custom action data"); hr = WcaWriteStringToCaData(pwzIconFile, &pwzCustomActionData); ExitOnFailure(hr, "failed to write icon file to custom action data"); hr = WcaWriteIntegerToCaData(iIconIndex, &pwzCustomActionData); ExitOnFailure(hr, "failed to write icon index to custom action data"); uiCost += COST_INTERNETSHORTCUT; } } if (E_NOMOREITEMS == hr) { hr = S_OK; } ExitOnFailure(hr, "Failure occured while processing WixInternetShortcut table"); // if we have any shortcuts to install if (pwzCustomActionData && *pwzCustomActionData) { // add cost to progress bar hr = WcaProgressMessage(uiCost, TRUE); ExitOnFailure(hr, "failed to extend progress bar for InternetShortcuts"); // provide custom action data to deferred and rollback CAs hr = WcaSetProperty(PLATFORM_DECORATION(L"WixRollbackInternetShortcuts"), pwzCustomActionData); ExitOnFailure(hr, "failed to set WixRollbackInternetShortcuts rollback custom action data"); hr = WcaSetProperty(PLATFORM_DECORATION(L"WixCreateInternetShortcuts"), pwzCustomActionData); ExitOnFailure(hr, "failed to set WixCreateInternetShortcuts custom action data"); } LExit: if (hCreateFolderTable) { ::MsiCloseHandle(hCreateFolderTable); } if (hCreateFolderColumns) { ::MsiCloseHandle(hCreateFolderColumns); } ReleaseStr(pwzCustomActionData); ReleaseStr(pwzComponent); ReleaseStr(pwzDirectory); ReleaseStr(pwzFilename); ReleaseStr(pwzTarget); ReleaseStr(pwzShortcutPath); ReleaseObject(piShellLink); ReleaseObject(piURL); if (fInitializedCom) { ::CoUninitialize(); } er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
static HRESULT RecursePath( __in_z LPCWSTR wzPath, __in_z LPCWSTR wzId, __in_z LPCWSTR wzComponent, __in_z LPCWSTR wzProperty, __in int iMode, __inout DWORD* pdwCounter, __inout MSIHANDLE* phTable, __inout MSIHANDLE* phColumns ) { HRESULT hr = S_OK; DWORD er; LPWSTR sczSearch = NULL; LPWSTR sczProperty = NULL; HANDLE hFind = INVALID_HANDLE_VALUE; WIN32_FIND_DATAW wfd; LPWSTR sczNext = NULL; // First recurse down to all the child directories. hr = StrAllocFormatted(&sczSearch, L"%s*", wzPath); ExitOnFailure1(hr, "Failed to allocate file search string in path: %S", wzPath); hFind = ::FindFirstFileW(sczSearch, &wfd); if (INVALID_HANDLE_VALUE == hFind) { er = ::GetLastError(); if (ERROR_PATH_NOT_FOUND == er) { ExitFunction1(hr = S_FALSE); } else { hr = HRESULT_FROM_WIN32(er); } ExitOnFailure1(hr, "Failed to find all files in path: %S", wzPath); } do { // Skip files and the dot directories. if (FILE_ATTRIBUTE_DIRECTORY != (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || L'.' == wfd.cFileName[0] && (L'\0' == wfd.cFileName[1] || (L'.' == wfd.cFileName[1] && L'\0' == wfd.cFileName[2]))) { continue; } hr = StrAllocFormatted(&sczNext, L"%s%s\\", wzPath, wfd.cFileName); ExitOnFailure2(hr, "Failed to concat filename '%S' to string: %S", wfd.cFileName, wzPath); hr = RecursePath(sczNext, wzId, wzComponent, wzProperty, iMode, pdwCounter, phTable, phColumns); ExitOnFailure1(hr, "Failed to recurse path: %S", sczNext); } while (::FindNextFileW(hFind, &wfd)); er = ::GetLastError(); if (ERROR_NO_MORE_FILES == er) { hr = S_OK; } else { hr = HRESULT_FROM_WIN32(er); ExitOnFailure1(hr, "Failed while looping through files in directory: %S", wzPath); } // Finally, set a property that points at our path. hr = StrAllocFormatted(&sczProperty, L"_%s_%u", wzProperty, *pdwCounter); ExitOnFailure1(hr, "Failed to allocate Property for RemoveFile table with property: %S.", wzProperty); ++(*pdwCounter); hr = WcaSetProperty(sczProperty, wzPath); ExitOnFailure2(hr, "Failed to set Property: %S with path: %S", sczProperty, wzPath); // Add the row to remove any files and another row to remove the folder. hr = WcaAddTempRecord(phTable, phColumns, L"RemoveFile", NULL, 1, 5, L"RfxFiles", wzComponent, L"*.*", sczProperty, iMode); ExitOnFailure2(hr, "Failed to add row to remove all files for WixRemoveFolderEx row: %S under path:", wzId, wzPath); hr = WcaAddTempRecord(phTable, phColumns, L"RemoveFile", NULL, 1, 5, L"RfxFolder", wzComponent, NULL, sczProperty, iMode); ExitOnFailure2(hr, "Failed to add row to remove folder for WixRemoveFolderEx row: %S under path: %S", wzId, wzPath); LExit: if (INVALID_HANDLE_VALUE != hFind) { ::FindClose(hFind); } ReleaseStr(sczNext); ReleaseStr(sczProperty); ReleaseStr(sczSearch); return hr; }
void CheckServiceConfig( wchar_t *my_servicename, /* SERVICENAME property in this installation*/ wchar_t *datadir, /* DATADIR property in this installation*/ wchar_t *bindir, /* INSTALLDIR\bin */ wchar_t *other_servicename, /* Service to check against */ QUERY_SERVICE_CONFIGW * config /* Other service's config */ ) { bool same_bindir = false; wchar_t * commandline= config->lpBinaryPathName; int numargs; wchar_t **argv= CommandLineToArgvW(commandline, &numargs); WcaLog(LOGMSG_VERBOSE, "CommandLine= %S", commandline); if(!argv || !argv[0] || ! wcsstr(argv[0], L"mysqld")) { goto end; } WcaLog(LOGMSG_STANDARD, "MySQL service %S found: CommandLine= %S", other_servicename, commandline); if (wcsstr(argv[0], bindir)) { WcaLog(LOGMSG_STANDARD, "executable under bin directory"); same_bindir = true; } bool is_my_service = (_wcsicmp(my_servicename, other_servicename) == 0); if(!is_my_service) { WcaLog(LOGMSG_STANDARD, "service does not match current service"); /* TODO probably the best thing possible would be to add temporary row to MSI ServiceConfig table with remove on uninstall */ } else if (!same_bindir) { WcaLog(LOGMSG_STANDARD, "Service name matches, but not the executable path directory, mine is %S", bindir); WcaSetProperty(L"SERVICENAME", L""); } /* Check if data directory is used */ if(!datadir || numargs <= 1 || wcsncmp(argv[1],L"--defaults-file=",16) != 0) { goto end; } wchar_t current_datadir_buf[MAX_PATH]={0}; wchar_t normalized_current_datadir[MAX_PATH+1]; wchar_t *current_datadir= current_datadir_buf; wchar_t *defaults_file= argv[1]+16; defaults_file= strip_quotes(defaults_file); WcaLog(LOGMSG_STANDARD, "parsed defaults file is %S", defaults_file); if (GetPrivateProfileStringW(L"mysqld", L"datadir", NULL, current_datadir, MAX_PATH, defaults_file) == 0) { WcaLog(LOGMSG_STANDARD, "Cannot find datadir in ini file '%S'", defaults_file); goto end; } WcaLog(LOGMSG_STANDARD, "datadir from defaults-file is %S", current_datadir); strip_quotes(current_datadir); /* Convert to Windows path */ if (GetFullPathNameW(current_datadir, MAX_PATH, normalized_current_datadir, NULL)) { /* Add backslash to be compatible with directory formats in MSI */ wcsncat(normalized_current_datadir, L"\\", MAX_PATH+1); WcaLog(LOGMSG_STANDARD, "normalized current datadir is '%S'", normalized_current_datadir); } if (_wcsicmp(datadir, normalized_current_datadir) == 0 && !same_bindir) { WcaLog(LOGMSG_STANDARD, "database directory from current installation, but different mysqld.exe"); WcaSetProperty(L"CLEANUPDATA", L""); } end: LocalFree((HLOCAL)argv); }
/****************************************************************** SchedNetFx - entry point for NetFx Custom Action ********************************************************************/ extern "C" UINT __stdcall SchedNetFx( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug SchedNetFx"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwzInstallCustomActionData = NULL; LPWSTR pwzUninstallCustomActionData = NULL; UINT uiCost = 0; PMSIHANDLE hView = NULL; PMSIHANDLE hRec = NULL; PMSIHANDLE hViewGac = NULL; PMSIHANDLE hRecGac = NULL; LPWSTR pwzId = NULL; LPWSTR pwzData = NULL; LPWSTR pwzTemp = NULL; LPWSTR pwzFile = NULL; int iPriority = 0; int iAssemblyCost = 0; int iAttributes = 0; LPWSTR pwzFileApp = NULL; LPWSTR pwzDirAppBase = NULL; LPWSTR pwzComponent = NULL; INSTALLSTATE isInstalled; INSTALLSTATE isAction; LPWSTR pwz32Ngen = NULL; LPWSTR pwz64Ngen = NULL; BOOL f32NgenExeExists = FALSE; BOOL f64NgenExeExists = FALSE; BOOL fNeedInstallUpdate32 = FALSE; BOOL fNeedUninstallUpdate32 = FALSE; BOOL fNeedInstallUpdate64 = FALSE; BOOL fNeedUninstallUpdate64 = FALSE; // initialize hr = WcaInitialize(hInstall, "SchedNetFx"); ExitOnFailure(hr, "failed to initialize"); hr = GetNgenPath(&pwz32Ngen, FALSE); f32NgenExeExists = SUCCEEDED(hr); if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) { hr = ERROR_SUCCESS; WcaLog(LOGMSG_STANDARD, "Failed to find 32bit ngen. No actions will be scheduled to create native images for 32bit."); } ExitOnFailure(hr, "failed to get 32bit ngen.exe path"); hr = GetNgenPath(&pwz64Ngen, TRUE); f64NgenExeExists = SUCCEEDED(hr); if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) { hr = ERROR_SUCCESS; WcaLog(LOGMSG_STANDARD, "Failed to find 64bit ngen. No actions will be scheduled to create native images for 64bit."); } ExitOnFailure(hr, "failed to get 64bit ngen.exe path"); // loop through all the NetFx records hr = WcaOpenExecuteView(vcsNgenQuery, &hView); ExitOnFailure(hr, "failed to open view on NetFxNativeImage table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { // Get Id hr = WcaGetRecordString(hRec, ngqId, &pwzId); ExitOnFailure(hr, "failed to get NetFxNativeImage.NetFxNativeImage"); // Get File hr = WcaGetRecordString(hRec, ngqFile, &pwzData); ExitOnFailure1(hr, "failed to get NetFxNativeImage.File_ for record: %ls", pwzId); hr = StrAllocFormatted(&pwzTemp, vpwzUnformattedQuotedFile, pwzData); ExitOnFailure1(hr, "failed to format file string for file: %ls", pwzData); hr = WcaGetFormattedString(pwzTemp, &pwzFile); ExitOnFailure1(hr, "failed to get formatted string for file: %ls", pwzData); // Get Priority hr = WcaGetRecordInteger(hRec, ngqPriority, &iPriority); ExitOnFailure1(hr, "failed to get NetFxNativeImage.Priority for record: %ls", pwzId); if (0 == iPriority) iAssemblyCost = COST_NGEN_BLOCKING; else iAssemblyCost = COST_NGEN_NONBLOCKING; // Get Attributes hr = WcaGetRecordInteger(hRec, ngqAttributes, &iAttributes); ExitOnFailure1(hr, "failed to get NetFxNativeImage.Attributes for record: %ls", pwzId); // Get File_Application or leave pwzFileApp NULL. hr = WcaGetRecordFormattedString(hRec, ngqFileApp, &pwzData); ExitOnFailure1(hr, "failed to get NetFxNativeImage.File_Application for record: %ls", pwzId); // Check if the value resolves to a valid file ID. if (S_OK == FileIdExists(pwzData)) { // Resolve the file ID to a path. hr = StrAllocFormatted(&pwzTemp, vpwzUnformattedQuotedFile, pwzData); ExitOnFailure1(hr, "failed to format file application string for file: %ls", pwzData); hr = WcaGetFormattedString(pwzTemp, &pwzFileApp); ExitOnFailure1(hr, "failed to get formatted string for file application: %ls", pwzData); } else { // Assume record formatted to a path already. hr = StrAllocString(&pwzFileApp, pwzData, 0); ExitOnFailure1(hr, "failed to allocate string for file path: %ls", pwzData); hr = PathEnsureQuoted(&pwzFileApp, FALSE); ExitOnFailure1(hr, "failed to quote file path: %ls", pwzData); } // Get Directory_ApplicationBase or leave pwzDirAppBase NULL. hr = WcaGetRecordFormattedString(hRec, ngqDirAppBase, &pwzData); ExitOnFailure1(hr, "failed to get NetFxNativeImage.Directory_ApplicationBase for record: %ls", pwzId); if (WcaIsUnicodePropertySet(pwzData)) { // Resolve the directory ID to a path. hr = StrAllocFormatted(&pwzTemp, vpwzUnformattedQuotedDirectory, pwzData); ExitOnFailure1(hr, "failed to format directory application base string for property: %ls", pwzData); hr = WcaGetFormattedString(pwzTemp, &pwzDirAppBase); ExitOnFailure1(hr, "failed to get formatted string for directory application base: %ls", pwzData); } else { // Assume record formatted to a path already. hr = StrAllocString(&pwzDirAppBase, pwzData, 0); ExitOnFailure1(hr, "failed to allocate string for directory path: %ls", pwzData); hr = PathEnsureQuoted(&pwzDirAppBase, TRUE); ExitOnFailure1(hr, "failed to quote and backslashify directory: %ls", pwzData); } // Get Component hr = WcaGetRecordString(hRec, ngqComponent, &pwzComponent); ExitOnFailure1(hr, "failed to get NetFxNativeImage.Directory_ApplicationBase for record: %ls", pwzId); er = ::MsiGetComponentStateW(hInstall, pwzComponent, &isInstalled, &isAction); ExitOnWin32Error1(er, hr, "failed to get install state for Component: %ls", pwzComponent); // // Figure out if it's going to be GAC'd. The possibility exists that no assemblies are going to be GAC'd // so we have to check for the MsiAssembly table first. // if (S_OK == WcaTableExists(L"MsiAssembly")) { hr = WcaOpenView(vcsNgenGac, &hViewGac); ExitOnFailure(hr, "failed to open view on File/MsiAssembly table"); hr = WcaExecuteView(hViewGac, hRec); ExitOnFailure(hr, "failed to execute view on File/MsiAssembly table"); hr = WcaFetchSingleRecord(hViewGac, &hRecGac); ExitOnFailure(hr, "failed to fetch File_Assembly from File/MsiAssembly table"); if (S_FALSE != hr) { hr = WcaGetRecordString(hRecGac, nggApplication, &pwzData); ExitOnFailure(hr, "failed to get MsiAssembly.File_Application"); // If it's in the GAC replace the file name with the strong name if (L'\0' == pwzData[0]) { hr = GetStrongName(&pwzFile, pwzComponent); ExitOnFailure1(hr, "failed to get strong name for component: %ls", pwzData); } } } // // Schedule the work // if (!(iAttributes & NGEN_32BIT) && !(iAttributes & NGEN_64BIT)) ExitOnFailure1(hr = E_INVALIDARG, "Neither 32bit nor 64bit is specified for NGEN of file: %ls", pwzFile); if (WcaIsInstalling(isInstalled, isAction) || WcaIsReInstalling(isInstalled, isAction)) { if (iAttributes & NGEN_32BIT && f32NgenExeExists) { // Assemble the install command line hr = CreateInstallCommand(&pwzData, pwz32Ngen, pwzFile, iPriority, iAttributes, pwzFileApp, pwzDirAppBase); ExitOnFailure(hr, "failed to create install command line"); hr = WcaWriteStringToCaData(pwzData, &pwzInstallCustomActionData); ExitOnFailure1(hr, "failed to add install command to custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(iAssemblyCost, &pwzInstallCustomActionData); ExitOnFailure1(hr, "failed to add cost to custom action data: %ls", pwzData); uiCost += iAssemblyCost; fNeedInstallUpdate32 = TRUE; } if (iAttributes & NGEN_64BIT && f64NgenExeExists) { // Assemble the install command line hr = CreateInstallCommand(&pwzData, pwz64Ngen, pwzFile, iPriority, iAttributes, pwzFileApp, pwzDirAppBase); ExitOnFailure(hr, "failed to create install command line"); hr = WcaWriteStringToCaData(pwzData, &pwzInstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(iAssemblyCost, &pwzInstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to custom action data: %ls", pwzData); uiCost += iAssemblyCost; fNeedInstallUpdate64 = TRUE; } } else if (WcaIsUninstalling(isInstalled, isAction)) { if (iAttributes & NGEN_32BIT && f32NgenExeExists) { hr = StrAllocFormatted(&pwzData, L"%s uninstall %s", pwz32Ngen, pwzFile); ExitOnFailure(hr, "failed to create update 32 command line"); hr = WcaWriteStringToCaData(pwzData, &pwzUninstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzUninstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to custom action data: %ls", pwzData); uiCost += COST_NGEN_NONBLOCKING; fNeedUninstallUpdate32 = TRUE; } if (iAttributes & NGEN_64BIT && f64NgenExeExists) { hr = StrAllocFormatted(&pwzData, L"%s uninstall %s", pwz64Ngen, pwzFile); ExitOnFailure(hr, "failed to create update 64 command line"); hr = WcaWriteStringToCaData(pwzData, &pwzUninstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzUninstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to custom action data: %ls", pwzData); uiCost += COST_NGEN_NONBLOCKING; fNeedUninstallUpdate64 = TRUE; } } } if (E_NOMOREITEMS == hr) hr = S_OK; ExitOnFailure(hr, "failed while looping through all files to create native images for"); // If we need 32 bit install update if (fNeedInstallUpdate32) { hr = StrAllocFormatted(&pwzData, L"%s update /queue", pwz32Ngen); ExitOnFailure(hr, "failed to create install update 32 command line"); hr = WcaWriteStringToCaData(pwzData, &pwzInstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to install custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzInstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to install custom action data: %ls", pwzData); uiCost += COST_NGEN_NONBLOCKING; } // If we need 32 bit uninstall update if (fNeedUninstallUpdate32) { hr = StrAllocFormatted(&pwzData, L"%s update /queue", pwz32Ngen); ExitOnFailure(hr, "failed to create uninstall update 32 command line"); hr = WcaWriteStringToCaData(pwzData, &pwzUninstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to uninstall custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzUninstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to uninstall custom action data: %ls", pwzData); uiCost += COST_NGEN_NONBLOCKING; } // If we need 64 bit install update if (fNeedInstallUpdate64) { hr = StrAllocFormatted(&pwzData, L"%s update /queue", pwz64Ngen); ExitOnFailure(hr, "failed to create install update 64 command line"); hr = WcaWriteStringToCaData(pwzData, &pwzInstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to install custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzInstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to install custom action data: %ls", pwzData); uiCost += COST_NGEN_NONBLOCKING; } // If we need 64 bit install update if (fNeedUninstallUpdate64) { hr = StrAllocFormatted(&pwzData, L"%s update /queue", pwz64Ngen); ExitOnFailure(hr, "failed to create uninstall update 64 command line"); hr = WcaWriteStringToCaData(pwzData, &pwzUninstallCustomActionData); // command ExitOnFailure1(hr, "failed to add install command to uninstall custom action data: %ls", pwzData); hr = WcaWriteIntegerToCaData(COST_NGEN_NONBLOCKING, &pwzUninstallCustomActionData); // cost ExitOnFailure1(hr, "failed to add cost to uninstall custom action data: %ls", pwzData); uiCost += COST_NGEN_NONBLOCKING; } // Add to progress bar if ((pwzInstallCustomActionData && *pwzInstallCustomActionData) || (pwzUninstallCustomActionData && *pwzUninstallCustomActionData)) { hr = WcaProgressMessage(uiCost, TRUE); ExitOnFailure(hr, "failed to extend progress bar for NetFxExecuteNativeImage"); } // Schedule the install custom action if (pwzInstallCustomActionData && *pwzInstallCustomActionData) { hr = WcaSetProperty(L"NetFxExecuteNativeImageInstall", pwzInstallCustomActionData); ExitOnFailure(hr, "failed to schedule NetFxExecuteNativeImageInstall action"); hr = WcaSetProperty(L"NetFxExecuteNativeImageCommitInstall", pwzInstallCustomActionData); ExitOnFailure(hr, "failed to schedule NetFxExecuteNativeImageCommitInstall action"); } // Schedule the uninstall custom action if (pwzUninstallCustomActionData && *pwzUninstallCustomActionData) { hr = WcaSetProperty(L"NetFxExecuteNativeImageUninstall", pwzUninstallCustomActionData); ExitOnFailure(hr, "failed to schedule NetFxExecuteNativeImageUninstall action"); hr = WcaSetProperty(L"NetFxExecuteNativeImageCommitUninstall", pwzUninstallCustomActionData); ExitOnFailure(hr, "failed to schedule NetFxExecuteNativeImageCommitUninstall action"); } LExit: ReleaseStr(pwzInstallCustomActionData); ReleaseStr(pwzUninstallCustomActionData); ReleaseStr(pwzId); ReleaseStr(pwzData); ReleaseStr(pwzTemp); ReleaseStr(pwzFile); ReleaseStr(pwzFileApp); ReleaseStr(pwzDirAppBase); ReleaseStr(pwzComponent); ReleaseStr(pwz32Ngen); ReleaseStr(pwz64Ngen); if (FAILED(hr)) er = ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
/******************************************************************** WixQueryOsDirs - entry point for WixQueryOsDirs custom action Called as Type 1 custom action (DLL from the Binary table) from Windows Installer to set properties that identify predefined directories ********************************************************************/ extern "C" UINT __stdcall WixQueryOsDirs( __in MSIHANDLE hInstall ) { HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; hr = WcaInitialize(hInstall, "WixQueryOsDirs"); ExitOnFailure(hr, "WixQueryOsDirs failed to initialize"); // get the paths of the CSIDLs that represent real paths and for which MSI // doesn't yet have standard folder properties WCHAR path[MAX_PATH]; if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_ADMINTOOLS, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_ADMINTOOLS", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_ALTSTARTUP, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_ALTSTARTUP", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_CDBURN_AREA, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_CDBURN_AREA", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_ADMINTOOLS, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_COMMON_ADMINTOOLS", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_ALTSTARTUP, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_COMMON_ALTSTARTUP", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_DOCUMENTS, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_COMMON_DOCUMENTS", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_FAVORITES, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_COMMON_FAVORITES", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_MUSIC, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_COMMON_MUSIC", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_PICTURES, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_COMMON_PICTURES", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COMMON_VIDEO, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_COMMON_VIDEO", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_COOKIES, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_COOKIES", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_DESKTOP, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_DESKTOP", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_HISTORY, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_HISTORY", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_INTERNET_CACHE, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_INTERNET_CACHE", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_MYMUSIC, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_MYMUSIC", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_MYPICTURES, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_MYPICTURES", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_MYVIDEO, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_MYVIDEO", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_NETHOOD, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_NETHOOD", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_PERSONAL", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_PRINTHOOD, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_PRINTHOOD", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_PROFILE", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_RECENT, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_RECENT", path); } if (ERROR_SUCCESS == ::SHGetFolderPathW(NULL, CSIDL_RESOURCES, NULL, SHGFP_TYPE_CURRENT, path)) { WcaSetProperty(L"WIX_DIR_RESOURCES", path); } LExit: if (FAILED(hr)) er = ERROR_INSTALL_FAILURE; return WcaFinalize(er); }