/******************************************************************** ReadEulaText - Reads Eula text from the MSI ********************************************************************/ HRESULT ReadEulaText( __in MSIHANDLE /*hInstall*/, __out LPSTR* ppszEulaText ) { HRESULT hr = S_OK; PMSIHANDLE hDB; PMSIHANDLE hView; PMSIHANDLE hRec; LPWSTR pwzEula = NULL; hr = WcaOpenExecuteView(vcsEulaQuery, &hView); ExitOnFailure(hr, "failed to open and execute view for PrintEula query"); hr = WcaFetchSingleRecord(hView, &hRec); ExitOnFailure(hr, "failed to fetch the row containing the LicenseText"); hr = WcaGetRecordString(hRec, 1, &pwzEula); ExitOnFailure(hr, "failed to get LicenseText in PrintEula"); hr = StrAnsiAllocString(ppszEulaText, pwzEula, 0, CP_ACP); ExitOnFailure(hr, "failed to convert LicenseText to ANSI code page"); LExit: return hr; }
HRESULT ScaVirtualDirGetComponent( __in LPCWSTR wzVirtualDir, __out LPWSTR* ppwzData ) { Assert(wzVirtualDir && *wzVirtualDir); HRESULT hr = S_OK; PMSIHANDLE hView, hRec; hr = WcaTableExists(L"IIsWebVirtualDir"); if (S_FALSE == hr) hr = E_ABORT; ExitOnFailure(hr, "IIsWebVirtualDir table does not exist or error"); hRec = ::MsiCreateRecord(1); if (!hRec) { hr = E_OUTOFMEMORY; ExitOnFailure(hr, "Failed to create record for lookup."); } hr = WcaSetRecordString(hRec, 1, wzVirtualDir); ExitOnFailure(hr, "Failed to look up VirtualDir Component"); hr = WcaOpenView(vcsVDirPropertiesQuery, &hView); ExitOnFailure(hr, "Failed to open view on VirtualDir"); hr = WcaExecuteView(hView, hRec); ExitOnFailure(hr, "Failed to exectue view on VirtualDir"); hr = WcaFetchSingleRecord(hView, &hRec); if (S_OK == hr) { #if DEBUG // check that vdir matches hr = WcaGetRecordString(hRec, vdqVDir, ppwzData); ExitOnFailure(hr, "Failed to get IIsWebVirtualDir.VirtualDir"); Assert(0 == lstrcmpW(*ppwzData, wzVirtualDir)); #endif hr = WcaGetRecordString(hRec, vdqComponent, ppwzData); ExitOnFailure(hr, "Failed to get Component for VirtualDir"); } else if (E_NOMOREITEMS == hr) { WcaLog(LOGMSG_STANDARD, "Error: Cannot locate IIsWebVirtualDir.VirtualDir='%S'", wzVirtualDir); hr = E_FAIL; } else { ExitOnFailure(hr, "Error or found multiple matching VirtualDir rows"); } LExit: return hr; }
static HRESULT GetUserAccountName( LPCWSTR pwzKey, LPWSTR* ppwzAccount ) { HRESULT hr = S_OK; PMSIHANDLE hView, hRecKey, hRec; LPWSTR pwzDomain = NULL; LPWSTR pwzName = NULL; // create parameter record hRecKey = ::MsiCreateRecord(1); ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record"); hr = WcaSetRecordString(hRecKey, 1, pwzKey); ExitOnFailure(hr, "Failed to set record string"); // open view hr = WcaOpenView(vcsUserQuery, &hView); ExitOnFailure(hr, "Failed to open view on User table"); hr = WcaExecuteView(hView, hRecKey); ExitOnFailure(hr, "Failed to execute view on User table"); // fetch record hr = WcaFetchSingleRecord(hView, &hRec); if (S_FALSE == hr) ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "User not found, key: %S", pwzKey); ExitOnFailure(hr, "Failed to fetch user record"); // get user domain hr = WcaGetRecordFormattedString(hRec, uqDomain, &pwzDomain); ExitOnFailure(hr, "Failed to get domain"); // get user name hr = WcaGetRecordFormattedString(hRec, uqName, &pwzName); ExitOnFailure(hr, "Failed to get name"); // build account name hr = CpiBuildAccountName(pwzDomain, pwzName, ppwzAccount); ExitOnFailure(hr, "Failed to build account name"); hr = S_OK; LExit: // clean up ReleaseStr(pwzDomain); ReleaseStr(pwzName); return hr; }
HRESULT CpiVerifyComponentArchitecure( LPCWSTR pwzComponent, BOOL* pfMatchingArchitecture ) { HRESULT hr = S_OK; PMSIHANDLE hView, hRecKey, hRec; int iAttributes = 0; if (S_OK == WcaTableExists(L"Component")) { // create parameter record hRecKey = ::MsiCreateRecord(1); ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record"); hr = WcaSetRecordString(hRecKey, 1, pwzComponent); ExitOnFailure(hr, "Failed to set record string"); // open view hr = WcaOpenView(vcsComponentAttributesQuery, &hView); ExitOnFailure(hr, "Failed to open view on ActionText table"); hr = WcaExecuteView(hView, hRecKey); ExitOnFailure(hr, "Failed to execute view on ActionText table"); // fetch record hr = WcaFetchSingleRecord(hView, &hRec); if (S_FALSE != hr) { ExitOnFailure(hr, "Failed to fetch component record"); hr = WcaGetRecordInteger(hRec, caqAttributes, &iAttributes); ExitOnFailure(hr, "Failed to get component attributes"); } } // return values #ifdef _WIN64 *pfMatchingArchitecture = 256 == (iAttributes & 256); #else *pfMatchingArchitecture = 256 != (iAttributes & 256); #endif hr = S_OK; LExit: return hr; }
// // ExtractBinary extracts the data from the Binary table row with the given ID into a file. // If wzDirectory is NULL, ExtractBinary defaults to the temporary directory. // HRESULT ExtractBinary( __in LPCWSTR wzBinaryId, __out BYTE** pbData, __out DWORD* pcbData ) { HRESULT hr = S_OK; LPWSTR pwzSql = NULL; PMSIHANDLE hView; PMSIHANDLE hRec; // make sure we're not horked from the get-go hr = WcaTableExists(L"Binary"); if (S_OK != hr) { if (SUCCEEDED(hr)) { hr = E_UNEXPECTED; } ExitOnFailure(hr, "There is no Binary table."); } ExitOnNull(wzBinaryId, hr, E_INVALIDARG, "Binary ID cannot be null"); ExitOnNull(*wzBinaryId, hr, E_INVALIDARG, "Binary ID cannot be empty string"); hr = StrAllocFormatted(&pwzSql, L"SELECT `Data` FROM `Binary` WHERE `Name`=\'%s\'", wzBinaryId); ExitOnFailure(hr, "Failed to allocate Binary table query."); hr = WcaOpenExecuteView(pwzSql, &hView); ExitOnFailure(hr, "Failed to open view on Binary table"); hr = WcaFetchSingleRecord(hView, &hRec); ExitOnFailure(hr, "Failed to retrieve request from Binary table"); hr = WcaGetRecordStream(hRec, 1, pbData, pcbData); ExitOnFailure(hr, "Failed to read Binary.Data."); LExit: ReleaseStr(pwzSql); return hr; }
/****************************************************************** FileIdExists - checks if the file ID is found in the File table returns S_OK if the file exists; S_FALSE if not; otherwise, error ********************************************************************/ static HRESULT FileIdExists( __in_opt LPCWSTR wzFile ) { HRESULT hr = S_OK; PMSIHANDLE hView = NULL; PMSIHANDLE hRec = NULL; if (!wzFile) { hr = S_FALSE; ExitFunction(); } hRec = ::MsiCreateRecord(1); hr = WcaSetRecordString(hRec, fiFile, wzFile); ExitOnFailure1(hr, "failed to create a record with the file: %ls", wzFile); hr = WcaTableExists(L"File"); if (S_OK == hr) { hr = WcaOpenView(vcsFileId, &hView); ExitOnFailure(hr, "failed to open view on File table"); hr = WcaExecuteView(hView, hRec); ExitOnFailure(hr, "failed to execute view on File table"); // Reuse the same record; the handle will be released. hr = WcaFetchSingleRecord(hView, &hRec); ExitOnFailure(hr, "failed to fetch File from File table"); } LExit: return hr; }
HRESULT __stdcall ScaGetUser( __in LPCWSTR wzUser, __out SCA_USER* pscau ) { if (!wzUser || !pscau) { return E_INVALIDARG; } HRESULT hr = S_OK; PMSIHANDLE hView, hRec; LPWSTR pwzData = NULL; // clear struct and bail right away if no user key was passed to search for ::ZeroMemory(pscau, sizeof(*pscau)); if (!*wzUser) { ExitFunction1(hr = S_OK); } hRec = ::MsiCreateRecord(1); hr = WcaSetRecordString(hRec, 1, wzUser); ExitOnFailure(hr, "Failed to look up User"); hr = WcaOpenView(vcsUserQuery, &hView); ExitOnFailure(hr, "Failed to open view on User table"); hr = WcaExecuteView(hView, hRec); ExitOnFailure(hr, "Failed to execute view on User table"); hr = WcaFetchSingleRecord(hView, &hRec); if (S_OK == hr) { hr = WcaGetRecordString(hRec, vuqUser, &pwzData); ExitOnFailure(hr, "Failed to get User.User"); hr = ::StringCchCopyW(pscau->wzKey, countof(pscau->wzKey), pwzData); ExitOnFailure(hr, "Failed to copy key string to user object"); hr = WcaGetRecordString(hRec, vuqComponent, &pwzData); ExitOnFailure(hr, "Failed to get User.Component_"); hr = ::StringCchCopyW(pscau->wzComponent, countof(pscau->wzComponent), pwzData); ExitOnFailure(hr, "Failed to copy component string to user object"); hr = WcaGetRecordFormattedString(hRec, vuqName, &pwzData); ExitOnFailure(hr, "Failed to get User.Name"); hr = ::StringCchCopyW(pscau->wzName, countof(pscau->wzName), pwzData); ExitOnFailure(hr, "Failed to copy name string to user object"); hr = WcaGetRecordFormattedString(hRec, vuqDomain, &pwzData); ExitOnFailure(hr, "Failed to get User.Domain"); hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData); ExitOnFailure(hr, "Failed to copy domain string to user object"); hr = WcaGetRecordFormattedString(hRec, vuqPassword, &pwzData); ExitOnFailure(hr, "Failed to get User.Password"); hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData); ExitOnFailure(hr, "Failed to copy password string to user object"); } else if (E_NOMOREITEMS == hr) { WcaLog(LOGMSG_STANDARD, "Error: Cannot locate User.User='******'", wzUser); hr = E_FAIL; } else { ExitOnFailure(hr, "Error or found multiple matching User rows"); } LExit: ReleaseStr(pwzData); return hr; }
HRESULT __stdcall ScaGetGroup( __in LPCWSTR wzGroup, __out SCA_GROUP* pscag ) { if (!wzGroup || !pscag) { return E_INVALIDARG; } HRESULT hr = S_OK; PMSIHANDLE hView, hRec; LPWSTR pwzData = NULL; hRec = ::MsiCreateRecord(1); hr = WcaSetRecordString(hRec, 1, wzGroup); ExitOnFailure(hr, "Failed to look up Group"); hr = WcaOpenView(vcsGroupQuery, &hView); ExitOnFailure(hr, "Failed to open view on Group table"); hr = WcaExecuteView(hView, hRec); ExitOnFailure(hr, "Failed to execute view on Group table"); hr = WcaFetchSingleRecord(hView, &hRec); if (S_OK == hr) { hr = WcaGetRecordString(hRec, vgqGroup, &pwzData); ExitOnFailure(hr, "Failed to get Group.Group"); hr = ::StringCchCopyW(pscag->wzKey, countof(pscag->wzKey), pwzData); ExitOnFailure(hr, "Failed to copy Group.Group."); hr = WcaGetRecordString(hRec, vgqComponent, &pwzData); ExitOnFailure(hr, "Failed to get Group.Component_"); hr = ::StringCchCopyW(pscag->wzComponent, countof(pscag->wzComponent), pwzData); ExitOnFailure(hr, "Failed to copy Group.Component_."); hr = WcaGetRecordFormattedString(hRec, vgqName, &pwzData); ExitOnFailure(hr, "Failed to get Group.Name"); hr = ::StringCchCopyW(pscag->wzName, countof(pscag->wzName), pwzData); ExitOnFailure(hr, "Failed to copy Group.Name."); hr = WcaGetRecordFormattedString(hRec, vgqDomain, &pwzData); ExitOnFailure(hr, "Failed to get Group.Domain"); hr = ::StringCchCopyW(pscag->wzDomain, countof(pscag->wzDomain), pwzData); ExitOnFailure(hr, "Failed to copy Group.Domain."); } else if (E_NOMOREITEMS == hr) { WcaLog(LOGMSG_STANDARD, "Error: Cannot locate Group.Group='%ls'", wzGroup); hr = E_FAIL; } else { ExitOnFailure(hr, "Error or found multiple matching Group rows"); } LExit: ReleaseStr(pwzData); return hr; }
/****************************************************************** CaSchedSecureObjects - entry point for CaReadSecureObjects Custom Action called as Type 1 CustomAction (binary DLL) from Windows Installer in InstallExecuteSequence before CaSecureObjects ******************************************************************/ extern "C" UINT __stdcall SchedSecureObjects( __in MSIHANDLE hInstall ) { // AssertSz(FALSE, "debug SchedSecureObjects"); HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; LPWSTR pwzData = NULL; LPWSTR pwzTable = NULL; LPWSTR pwzTargetPath = NULL; LPWSTR pwzFormattedString = NULL; int iRoot = 0; int iAllUsers = 0; LPWSTR pwzKey = NULL; PMSIHANDLE hView = NULL; PMSIHANDLE hRec = NULL; MSIHANDLE hViewObject = NULL; // Don't free this since it's always a copy of either hViewService or hViewCreateFolder PMSIHANDLE hViewService = NULL; PMSIHANDLE hViewCreateFolder = NULL; PMSIHANDLE hViewFile = NULL; PMSIHANDLE hViewRegistry = NULL; PMSIHANDLE hRecObject = NULL; INSTALLSTATE isInstalled; INSTALLSTATE isAction; LPWSTR pwzCustomActionData = NULL; DWORD cchCustomActionData = 0; DWORD cObjects = 0; eOBJECTTYPE eType = OT_UNKNOWN; // // initialize // hr = WcaInitialize(hInstall, "SchedSecureObjects"); ExitOnFailure(hr, "failed to initialize"); // // loop through all the objects to be secured // hr = WcaOpenExecuteView(wzQUERY_SECUREOBJECTS, &hView); ExitOnFailure(hr, "failed to open view on SecureObjects table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { hViewObject = NULL; eType = OT_UNKNOWN; hr = WcaGetRecordString(hRec, QSO_TABLE, &pwzTable); ExitOnFailure(hr, "failed to get object table"); // ensure we're looking at a known table if (0 == lstrcmpW(L"ServiceInstall", pwzTable)) { eType = OT_SERVICE; } else if (0 == lstrcmpW(L"CreateFolder", pwzTable)) { eType = OT_FOLDER; } else if (0 == lstrcmpW(L"File", pwzTable)) { eType = OT_FILE; } else if (0 == lstrcmpW(L"Registry", pwzTable)) { eType = OT_REGISTRY; } else { ExitOnFailure1(hr = E_INVALIDARG, "unknown SecureObject.Table: %S", pwzTable); } // if we haven't opened a view on the ServiceInstall/CreateFolder table, do that now if (OT_SERVICE == eType) { if (!hViewService) { hr = WcaTableExists(pwzTable); if (S_FALSE == hr) hr = E_UNEXPECTED; ExitOnFailure1(hr, "failed to open %s table to secure object", pwzTable); hr = WcaOpenView(wzQUERY_SERVICECOMPONENT, &hViewService); ExitOnFailure(hr, "failed to open view on ServiceInstall table"); } hViewObject = hViewService; } else if (OT_FOLDER == eType) { if (!hViewCreateFolder) { hr = WcaTableExists(pwzTable); if (S_FALSE == hr) hr = E_UNEXPECTED; ExitOnFailure1(hr, "failed to open %s table to secure object", pwzTable); hr = WcaOpenView(wzQUERY_CREATEFOLDERCOMPONENT, &hViewCreateFolder); ExitOnFailure(hr, "failed to open view on CreateFolder table"); } hViewObject = hViewCreateFolder; } else if (OT_FILE== eType) { if (!hViewFile) { hr = WcaTableExists(pwzTable); if (S_FALSE == hr) hr = E_UNEXPECTED; ExitOnFailure1(hr, "failed to open %s table to secure object", pwzTable); hr = WcaOpenView(wzQUERY_FILECOMPONENT, &hViewFile); ExitOnFailure(hr, "failed to open view on CreateFolder table"); } hViewObject = hViewFile; } else if (OT_REGISTRY== eType) { if (!hViewRegistry) { hr = WcaTableExists(pwzTable); if (S_FALSE == hr) hr = E_UNEXPECTED; ExitOnFailure1(hr, "failed to open %s table to secure object", pwzTable); hr = WcaOpenView(wzQUERY_REGISTRYCOMPONENT, &hViewRegistry); ExitOnFailure(hr, "failed to open view on CreateFolder table"); } hViewObject = hViewRegistry; } Assert(hViewObject); // execute a view looking for the object's Component_ hr = WcaExecuteView(hViewObject, hRec); ExitOnFailure1(hr, "failed to execute view on %S table", pwzData); hr = WcaFetchSingleRecord(hViewObject, &hRecObject); ExitOnFailure(hr, "failed to fetch Component for secure object"); hr = WcaGetRecordString(hRecObject, QSOC_COMPONENT, &pwzData); ExitOnFailure(hr, "failed to get Component name for secure object"); // // if we are installing this Component // er = ::MsiGetComponentStateW(hInstall, pwzData, &isInstalled, &isAction); ExitOnFailure1(hr = HRESULT_FROM_WIN32(er), "failed to get install state for Component: %S", pwzData); if (WcaIsInstalling(isInstalled, isAction)) { // add the data to the CustomActionData hr = WcaGetRecordString(hRecObject, QSOC_OBJECTNAME, &pwzData); ExitOnFailure(hr, "failed to get name of object"); if (OT_SERVICE == eType) { hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); } else if (OT_FOLDER == eType) { hr = WcaGetTargetPath(pwzData, &pwzTargetPath); ExitOnFailure1(hr, "failed to get target path for directory id: %S", pwzData); hr = WcaWriteStringToCaData(pwzTargetPath, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); } else if (OT_FILE == eType) { hr = StrAllocFormatted(&pwzFormattedString, L"[#%s]", pwzData); ExitOnFailure1(hr, "failed to create formatted string for securing file object: %S", pwzData); hr = WcaGetFormattedString(pwzFormattedString, &pwzTargetPath); ExitOnFailure2(hr, "failed to get file path from formatted string: %S for secure object: %S", pwzFormattedString, pwzData); hr = WcaWriteStringToCaData(pwzTargetPath, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); } else if (OT_REGISTRY == eType) { hr = WcaGetRecordInteger(hRecObject, QSOC_REGROOT, &iRoot); ExitOnFailure1(hr, "Failed to get reg key root for secure object: %S", pwzData); hr = WcaGetRecordFormattedString(hRecObject, QSOC_REGKEY, &pwzKey); ExitOnFailure1(hr, "Failed to get reg key for secure object: %S", pwzData); // Decode the root value if (-1 == iRoot) { // They didn't specify a root so that means it's either HKCU or HKLM depending on ALLUSERS property hr = WcaGetIntProperty(L"ALLUSERS", &iAllUsers); ExitOnFailure(hr, "failed to get value of ALLUSERS property"); if (1 == iAllUsers) { hr = StrAllocString(&pwzTargetPath, L"MACHINE\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKLM root"); } else { hr = StrAllocString(&pwzTargetPath, L"CURRENT_USER\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKCU root"); } } else if (/*msidbRegistryRootClassesRoot*/ 0 == iRoot) { hr = StrAllocString(&pwzTargetPath, L"CLASSES_ROOT\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKCR root"); } else if (/*msidbRegistryRootCurrentUser*/ 1 == iRoot) { hr = StrAllocString(&pwzTargetPath, L"CURRENT_USER\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKCU root"); } else if (/*msidbRegistryRootLocalMachine*/ 2 == iRoot) { hr = StrAllocString(&pwzTargetPath, L"MACHINE\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKLM root"); } else if (/*msidbRegistryRootUsers*/ 3 == iRoot) { hr = StrAllocString(&pwzTargetPath, L"USERS\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKU root"); } else { ExitOnFailure2(hr = E_UNEXPECTED, "Unknown registry key root specified for secure object: '%S' root: %d", pwzData, iRoot); } hr = StrAllocConcat(&pwzTargetPath, pwzKey, 0); ExitOnFailure2(hr, "Failed to concat key: %S for secure object: %S", pwzKey, pwzData); hr = WcaWriteStringToCaData(pwzTargetPath, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); } else { AssertSz(FALSE, "How did you get here?"); } hr = WcaWriteStringToCaData(pwzTable, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordFormattedString(hRec, QSO_DOMAIN, &pwzData); ExitOnFailure(hr, "failed to get domain for user to configure object"); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordFormattedString(hRec, QSO_USER, &pwzData); ExitOnFailure(hr, "failed to get user to configure object"); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); hr = WcaGetRecordString(hRec, QSO_PERMISSION, &pwzData); ExitOnFailure(hr, "failed to get domain for user to configure object"); hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData); ExitOnFailure(hr, "failed to add data to CustomActionData"); cObjects++; } } // if we looped through all records all is well if (E_NOMOREITEMS == hr) hr = S_OK; ExitOnFailure(hr, "failed while looping through all objects to secure"); // // schedule the custom action and add to progress bar // if (pwzCustomActionData && *pwzCustomActionData) { Assert(0 < cObjects); hr = WcaDoDeferredAction(L"ExecSecureObjects", pwzCustomActionData, cObjects * COST_SECUREOBJECT); ExitOnFailure(hr, "failed to schedule ExecSecureObjects action"); } LExit: ReleaseStr(pwzCustomActionData); ReleaseStr(pwzData); ReleaseStr(pwzTable); ReleaseStr(pwzTargetPath); ReleaseStr(pwzFormattedString); ReleaseStr(pwzKey); if (FAILED(hr)) er = ERROR_INSTALL_FAILURE; return WcaFinalize(er); }
HRESULT CpiAddActionTextToActionData( LPCWSTR pwzAction, LPWSTR* ppwzActionData ) { HRESULT hr = S_OK; PMSIHANDLE hView, hRecKey, hRec; LPWSTR pwzDescription = NULL; LPWSTR pwzTemplate = NULL; if (S_OK == WcaTableExists(L"ActionText")) { // create parameter record hRecKey = ::MsiCreateRecord(1); ExitOnNull(hRecKey, hr, E_OUTOFMEMORY, "Failed to create record"); hr = WcaSetRecordString(hRecKey, 1, pwzAction); ExitOnFailure(hr, "Failed to set record string"); // open view hr = WcaOpenView(vcsActionTextQuery, &hView); ExitOnFailure(hr, "Failed to open view on ActionText table"); hr = WcaExecuteView(hView, hRecKey); ExitOnFailure(hr, "Failed to execute view on ActionText table"); // fetch record hr = WcaFetchSingleRecord(hView, &hRec); if (S_FALSE != hr) { ExitOnFailure(hr, "Failed to fetch action text record"); // get description hr = WcaGetRecordString(hRec, atqDescription, &pwzDescription); ExitOnFailure(hr, "Failed to get description"); // get template hr = WcaGetRecordString(hRec, atqTemplate, &pwzTemplate); ExitOnFailure(hr, "Failed to get template"); } } // add action name to action data hr = WcaWriteStringToCaData(pwzAction, ppwzActionData); ExitOnFailure(hr, "Failed to add action name to custom action data"); // add description to action data hr = WcaWriteStringToCaData(pwzDescription ? pwzDescription : L"", ppwzActionData); ExitOnFailure(hr, "Failed to add description to custom action data"); // add template to action data hr = WcaWriteStringToCaData(pwzTemplate ? pwzTemplate : L"", ppwzActionData); ExitOnFailure(hr, "Failed to add template to custom action data"); hr = S_OK; LExit: // clean up ReleaseStr(pwzDescription); ReleaseStr(pwzTemplate); return hr; }
HRESULT ScaSqlStrsReadScripts( __inout SCA_SQLSTR** ppsssList, __in SCA_ACTION saAction ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; PMSIHANDLE hView, hRec; PMSIHANDLE hViewBinary, hRecBinary; PMSIHANDLE hViewUser, hRecUser; LPWSTR pwzComponent = NULL; LPWSTR pwzData = NULL; BYTE* pbScript = NULL; DWORD cbRead = 0; DWORD cbScript = 0; DWORD cchScript = 0; LPWSTR pwzScriptBuffer = NULL; WCHAR* pwzScript = NULL; WCHAR* pwz; DWORD cch = 0; SCA_SQLSTR sss; SCA_SQLSTR* psss = NULL; if (S_OK != WcaTableExists(L"SqlScript") || S_OK != WcaTableExists(L"SqlDatabase") || S_OK != WcaTableExists(L"Binary")) { WcaLog(LOGMSG_VERBOSE, "Skipping ScaSqlStrsReadScripts() - SqlScripts and/or SqlDatabase table not present"); ExitFunction1(hr = S_FALSE); } // open a view on the binary table hr = WcaOpenView(vcsSqlBinaryScriptQuery, &hViewBinary); ExitOnFailure(hr, "Failed to open view on Binary table for SqlScripts"); // loop through all the sql scripts hr = WcaOpenExecuteView(vcsSqlScriptQuery, &hView); ExitOnFailure(hr, "Failed to open view on SqlScript table"); while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) { INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; hr = WcaGetRecordString(hRec, sscrqComponent, &pwzComponent); ExitOnFailure(hr, "Failed to get Component for SQL Script."); er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &isInstalled, &isAction); hr = HRESULT_FROM_WIN32(er); ExitOnFailure1(hr, "Failed to get state for component: %ls", pwzComponent); // If we're doing install but the Component is not being installed or we're doing // uninstall but the Component is not being uninstalled, skip it. if ((WcaIsInstalling(isInstalled, isAction) && SCA_ACTION_INSTALL != saAction) || (WcaIsUninstalling(isInstalled, isAction) && SCA_ACTION_UNINSTALL != saAction)) { continue; } ::ZeroMemory(&sss, sizeof(sss)); sss.isInstalled = isInstalled; sss.isAction = isAction; hr = WcaGetRecordString(hRec, sscrqSqlScript, &pwzData); ExitOnFailure(hr, "Failed to get SqlScript.Script"); hr = ::StringCchCopyW(sss.wzKey, countof(sss.wzKey), pwzData); ExitOnFailure1(hr, "Failed to copy SqlScript.Script: %ls", pwzData); // find the database information for this string hr = WcaGetRecordString(hRec, sscrqSqlDb, &pwzData); ExitOnFailure1(hr, "Failed to get SqlScript.SqlDb_ for SqlScript '%ls'", sss.wzKey); hr = ::StringCchCopyW(sss.wzSqlDb, countof(sss.wzSqlDb), pwzData); ExitOnFailure1(hr, "Failed to copy SqlScritp.SqlDbb: %ls", pwzData); hr = WcaGetRecordInteger(hRec, sscrqAttributes, &sss.iAttributes); ExitOnFailure1(hr, "Failed to get SqlScript.Attributes for SqlScript '%ls'", sss.wzKey); hr = WcaGetRecordInteger(hRec, sscrqSequence, &sss.iSequence); ExitOnFailure1(hr, "Failed to get SqlScript.Sequence for SqlScript '%ls'", sss.wzKey); // get the sql script out of the binary stream hr = WcaExecuteView(hViewBinary, hRec); ExitOnFailure1(hr, "Failed to open SqlScript.BinaryScript_ for SqlScript '%ls'", sss.wzKey); hr = WcaFetchSingleRecord(hViewBinary, &hRecBinary); ExitOnFailure1(hr, "Failed to fetch SqlScript.BinaryScript_ for SqlScript '%ls'", sss.wzKey); // Note: We need to allocate an extra character on the stream to NULL terminate the SQL script. // The WcaGetRecordStream() function won't let us add extra space on the end of the stream // so we'll read the stream "the old fashioned way". //hr = WcaGetRecordStream(hRecBinary, ssbsqData, (BYTE**)&pbScript, &cbScript); //ExitOnFailure1(hr, "Failed to read SqlScript.BinaryScript_ for SqlScript '%ls'", sss.wzKey); er = ::MsiRecordReadStream(hRecBinary, ssbsqData, NULL, &cbRead); hr = HRESULT_FROM_WIN32(er); ExitOnFailure(hr, "failed to get size of stream"); cbScript = cbRead + sizeof(WCHAR); // we may have an ANSI SQL script but leave enough to even NULL terminate a WCHAR string hr = WcaAllocStream(&pbScript, cbScript); // this will allocate a fully zeroed out buffer so our string will be NULL terminated ExitOnFailure(hr, "failed to allocate data for stream"); er = ::MsiRecordReadStream(hRecBinary, ssbsqData, reinterpret_cast<char*>(pbScript), &cbRead); //read the buffer but leave the space for the NULL terminator hr = HRESULT_FROM_WIN32(er); ExitOnFailure(hr, "failed to read from stream"); Assert(cbRead + sizeof(WCHAR) == cbScript); // Check for the UNICODE BOM file marker. if ((0xFF == *pbScript) && (0xFE == *(pbScript + 1))) { // Copy the UNICODE string after the BOM marker (subtract one because we'll skip the BOM marker). cchScript = (cbScript / sizeof(WCHAR)) - 1; hr = StrAllocString(&pwzScriptBuffer, reinterpret_cast<LPWSTR>(pbScript) + 1, 0); ExitOnFailure1(hr, "Failed to allocate WCHAR string of size '%d'", cchScript); } else { // We have an ANSI string so convert it to UNICODE. cchScript = cbScript; hr = StrAllocStringAnsi(&pwzScriptBuffer, reinterpret_cast<LPCSTR>(pbScript), 0, CP_ACP); ExitOnFailure1(hr, "Failed to allocate WCHAR string of size '%d'", cchScript); } // Free the byte buffer since it has been converted to a new UNICODE string, one way or another. if (pbScript) { WcaFreeStream(pbScript); pbScript = NULL; } // Process the SQL script stripping out unnecessary stuff (like comments) and looking for "GO" statements. pwzScript = pwzScriptBuffer; while (cchScript && pwzScript && *pwzScript) { // strip off leading whitespace while (cchScript && *pwzScript && iswspace(*pwzScript)) { ++pwzScript; --cchScript; } Assert(0 <= cchScript); // if there is a SQL comment remove it while (cchScript && L'/' == *pwzScript && L'*' == *(pwzScript + 1)) { // go until end of comment while (cchScript && *pwzScript && *(pwzScript + 1) && !(L'*' == *pwzScript && L'/' == *(pwzScript + 1))) { ++pwzScript; --cchScript; } Assert(2 <= cchScript); if (2 <= cchScript) { // to account for */ at end pwzScript+=2; cchScript-=2; } Assert(0 <= cchScript); // strip off any new leading whitespace while (cchScript && *pwzScript && iswspace(*pwzScript)) { ++pwzScript; --cchScript; } } while (cchScript && L'-' == *pwzScript && L'-' == *(pwzScript + 1)) { // go past the new line character while (cchScript && *pwzScript && L'\n' != *pwzScript) { ++pwzScript; --cchScript; } Assert(0 <= cchScript); if (cchScript && L'\n' == *pwzScript) { ++pwzScript; --cchScript; } Assert(0 <= cchScript); // strip off any new leading whitespace while (cchScript && *pwzScript && iswspace(*pwzScript)) { ++pwzScript; --cchScript; } } Assert(0 <= cchScript); // try to isolate a "GO" keyword and count the characters in the SQL string pwz = pwzScript; cch = 0; while (cchScript && *pwz) { //skip past comment lines that might have "go" in them //note that these comments are "in the middle" of our function, //or possibly at the end of a line if (cchScript && L'-' == *pwz && L'-' == *(pwz + 1)) { // skip past chars until the new line character while (cchScript && *pwz && (L'\n' != *pwz)) { ++pwz; ++cch; --cchScript; } } //skip past comment lines of form /* to */ that might have "go" in them //note that these comments are "in the middle" of our function, //or possibly at the end of a line if (cchScript && L'/' == *pwz && L'*' == *(pwz + 1)) { // skip past chars until the new line character while (cchScript && *pwz && *(pwz + 1) && !((L'*' == *pwz) && (L'/' == *(pwz + 1)))) { ++pwz; ++cch; --cchScript; } if (2 <= cchScript) { // to account for */ at end pwz+=2; cch+=2; cchScript-=2; } } // Skip past strings that may be part of the SQL statement that might have a "go" in them if ( cchScript && L'\'' == *pwz ) { ++pwz; ++cch; --cchScript; // Skip past chars until the end of the string while ( cchScript && *pwz && !(L'\'' == *pwz) ) { ++pwz; ++cch; --cchScript; } } // Skip past strings that may be part of the SQL statement that might have a "go" in them if ( cchScript && L'\"' == *pwz ) { ++pwz; ++cch; --cchScript; // Skip past chars until the end of the string while ( cchScript && *pwz && !(L'\"' == *pwz) ) { ++pwz; ++cch; --cchScript; } } // if "GO" is isolated if ((pwzScript == pwz || iswspace(*(pwz - 1))) && (L'G' == *pwz || L'g' == *pwz) && (L'O' == *(pwz + 1) || L'o' == *(pwz + 1)) && (0 == *(pwz + 2) || iswspace(*(pwz + 2)))) { *pwz = 0; // null terminate the SQL string on the "G" pwz += 2; cchScript -= 2; break; // found "GO" now add SQL string to list } ++pwz; ++cch; --cchScript; } Assert(0 <= cchScript); if (0 < cch) //don't process if there's nothing to process { // replace tabs with spaces for (LPWSTR pwzTab = wcsstr(pwzScript, L"\t"); pwzTab; pwzTab = wcsstr(pwzTab, L"\t")) *pwzTab = ' '; // strip off whitespace at the end of the script string for (LPWSTR pwzErase = pwzScript + cch - 1; pwzScript < pwzErase && iswspace(*pwzErase); pwzErase--) { *(pwzErase) = 0; cch--; } } if (0 < cch) { hr = NewSqlStr(&psss); ExitOnFailure(hr, "failed to allocate new sql string element"); // copy everything over hr = ::StringCchCopyW(psss->wzKey, countof(psss->wzKey), sss.wzKey); ExitOnFailure(hr, "Failed to copy key string to sqlstr object"); hr = ::StringCchCopyW(psss->wzSqlDb, countof(psss->wzSqlDb), sss.wzSqlDb); ExitOnFailure(hr, "Failed to copy DB string to sqlstr object"); hr = ::StringCchCopyW(psss->wzComponent, countof(psss->wzComponent), sss.wzComponent); ExitOnFailure(hr, "Failed to copy component string to sqlstr object"); psss->isInstalled = sss.isInstalled; psss->isAction = sss.isAction; psss->iAttributes = sss.iAttributes; psss->iSequence = sss.iSequence; // cchRequired includes the NULL terminating char hr = StrAllocString(&psss->pwzSql, pwzScript, 0); ExitOnFailure1(hr, "Failed to allocate string for SQL script: '%ls'", psss->wzKey); *ppsssList = AddSqlStrToList(*ppsssList, psss); psss = NULL; // set the db NULL so it doesn't accidentally get freed below } pwzScript = pwz; } } if (E_NOMOREITEMS == hr) { hr = S_OK; } ExitOnFailure(hr, "Failure occured while reading SqlString table"); LExit: // if anything was left over after an error clean it all up if (psss) { ScaSqlStrsFreeList(psss); } if (pbScript) { WcaFreeStream(pbScript); } ReleaseStr(pwzScriptBuffer); ReleaseStr(pwzData); ReleaseStr(pwzComponent); return hr; }
static HRESULT GetTargetPath( __in eOBJECTTYPE eType, __in LPCWSTR pwzSecureObject, __out LPWSTR* ppwzTargetPath ) { HRESULT hr = S_OK; PMSIHANDLE hView = NULL; PMSIHANDLE hRecObject = NULL; PMSIHANDLE hRec = NULL; int iRoot = 0; int iAllUsers = 0; LPWSTR pwzKey = NULL; LPWSTR pwzFormattedString = NULL; if (OT_SERVICE == eType) { hr = WcaTableExists(L"ServiceInstall"); if (S_FALSE == hr) { hr = E_UNEXPECTED; } ExitOnFailure(hr, "failed to open ServiceInstall table to secure object"); hr = WcaOpenView(wzQUERY_SERVICEINSTALL, &hView); ExitOnFailure(hr, "failed to open view on ServiceInstall table"); // create a record that stores the object to secure hRec = MsiCreateRecord(1); MsiRecordSetStringW(hRec, 1, pwzSecureObject); // execute a view looking for the object's ServiceInstall.ServiceInstall row. hr = WcaExecuteView(hView, hRec); ExitOnFailure(hr, "failed to execute view on ServiceInstall table"); hr = WcaFetchSingleRecord(hView, &hRecObject); ExitOnFailure(hr, "failed to fetch ServiceInstall row for secure object"); hr = WcaGetRecordFormattedString(hRecObject, QSSI_NAME, ppwzTargetPath); ExitOnFailure1(hr, "failed to get service name for secure object: %ls", pwzSecureObject); } else if (OT_FOLDER == eType) { hr = WcaGetTargetPath(pwzSecureObject, ppwzTargetPath); ExitOnFailure1(hr, "failed to get target path for directory id: %ls", pwzSecureObject); } else if (OT_FILE == eType) { hr = StrAllocFormatted(&pwzFormattedString, L"[#%s]", pwzSecureObject); ExitOnFailure1(hr, "failed to create formatted string for securing file object: %ls", pwzSecureObject); hr = WcaGetFormattedString(pwzFormattedString, ppwzTargetPath); ExitOnFailure2(hr, "failed to get file path from formatted string: %ls for secure object: %ls", pwzFormattedString, pwzSecureObject); } else if (OT_REGISTRY == eType) { hr = WcaTableExists(L"Registry"); if (S_FALSE == hr) { hr = E_UNEXPECTED; } ExitOnFailure(hr, "failed to open Registry table to secure object"); hr = WcaOpenView(wzQUERY_REGISTRY, &hView); ExitOnFailure(hr, "failed to open view on Registry table"); // create a record that stores the object to secure hRec = MsiCreateRecord(1); MsiRecordSetStringW(hRec, 1, pwzSecureObject); // execute a view looking for the object's Registry row hr = WcaExecuteView(hView, hRec); ExitOnFailure(hr, "failed to execute view on Registry table"); hr = WcaFetchSingleRecord(hView, &hRecObject); ExitOnFailure(hr, "failed to fetch Registry row for secure object"); hr = WcaGetRecordInteger(hRecObject, QSOC_REGROOT, &iRoot); ExitOnFailure1(hr, "Failed to get reg key root for secure object: %ls", pwzSecureObject); hr = WcaGetRecordFormattedString(hRecObject, QSOC_REGKEY, &pwzKey); ExitOnFailure1(hr, "Failed to get reg key for secure object: %ls", pwzSecureObject); // Decode the root value if (-1 == iRoot) { // They didn't specify a root so that means it's either HKCU or HKLM depending on ALLUSERS property hr = WcaGetIntProperty(L"ALLUSERS", &iAllUsers); ExitOnFailure(hr, "failed to get value of ALLUSERS property"); if (1 == iAllUsers) { hr = StrAllocString(ppwzTargetPath, L"MACHINE\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKLM root"); } else { hr = StrAllocString(ppwzTargetPath, L"CURRENT_USER\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKCU root"); } } else if (msidbRegistryRootClassesRoot == iRoot) { hr = StrAllocString(ppwzTargetPath, L"CLASSES_ROOT\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKCR root"); } else if (msidbRegistryRootCurrentUser == iRoot) { hr = StrAllocString(ppwzTargetPath, L"CURRENT_USER\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKCU root"); } else if (msidbRegistryRootLocalMachine == iRoot) { hr = StrAllocString(ppwzTargetPath, L"MACHINE\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKLM root"); } else if (msidbRegistryRootUsers == iRoot) { hr = StrAllocString(ppwzTargetPath, L"USERS\\", 0); ExitOnFailure(hr, "failed to allocate target registry string with HKU root"); } else { ExitOnFailure2(hr = E_UNEXPECTED, "Unknown registry key root specified for secure object: '%ls' root: %d", pwzSecureObject, iRoot); } hr = StrAllocConcat(ppwzTargetPath, pwzKey, 0); ExitOnFailure2(hr, "Failed to concat key: %ls for secure object: %ls", pwzKey, pwzSecureObject); } else { AssertSz(FALSE, "How did you get here?"); ExitOnFailure1(hr = E_UNEXPECTED, "Unknown secure object type: %d", eType); } LExit: ReleaseStr(pwzFormattedString); ReleaseStr(pwzKey); return hr; }
/****************************************************************** 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); }
HRESULT GetFileSpec( __in MSIHANDLE hViewFileSpec, __in LPCWSTR wzKey, __in SQL_FILESPEC* psf ) { HRESULT hr = S_OK; PMSIHANDLE hRecFileSpec, hRec; LPWSTR pwzData = NULL; // create a record to do the fetch hRecFileSpec = ::MsiCreateRecord(1); if (!hRecFileSpec) { ExitOnFailure1(hr = E_UNEXPECTED, "failed to create record for filespec: %ls", wzKey); } hr = WcaSetRecordString(hRecFileSpec, 1, wzKey); ExitOnFailure1(hr, "failed to set record string for filespec: %ls", wzKey); // get the FileSpec record hr = WcaExecuteView(hViewFileSpec, hRecFileSpec); ExitOnFailure1(hr, "failed to execute view on SqlFileSpec table for filespec: %ls", wzKey); hr = WcaFetchSingleRecord(hViewFileSpec, &hRec); ExitOnFailure1(hr, "failed to get record for filespec: %ls", wzKey); // read the data out of the filespec record hr = WcaGetRecordFormattedString(hRec, sfsqName, &pwzData); ExitOnFailure1(hr, "Failed to get SqlFileSpec.Name for filespec: %ls", wzKey); hr = ::StringCchCopyW(psf->wzName, countof(psf->wzName), pwzData); ExitOnFailure1(hr, "Failed to copy SqlFileSpec.Name string: %ls", pwzData); hr = WcaGetRecordFormattedString(hRec, sfsqFilename, &pwzData); ExitOnFailure1(hr, "Failed to get SqlFileSpec.Filename for filespec: %ls", wzKey); if (*pwzData) { hr = ::StringCchCopyW(psf->wzFilename, countof(psf->wzFilename), pwzData); ExitOnFailure1(hr, "Failed to copy filename to filespec object: %ls", pwzData); } else // if there is no file, skip this FILESPEC { WcaLog(LOGMSG_VERBOSE, "No filename specified, skipping FileSpec: %ls", psf->wzName); ExitFunction1(hr = S_FALSE); } hr = WcaGetRecordFormattedString(hRec, sfsqSize, &pwzData); ExitOnFailure1(hr, "Failed to get SqlFileSpec.Size for filespec: %ls", wzKey); if (*pwzData) { hr = ::StringCchCopyW(psf->wzSize, countof(psf->wzSize), pwzData); ExitOnFailure1(hr, "Failed to copy size to filespec object: %ls", pwzData); } else { psf->wzSize[0] = 0; } hr = WcaGetRecordFormattedString(hRec, sfsqMaxSize, &pwzData); ExitOnFailure1(hr, "Failed to get SqlFileSpec.MaxSize for filespec: %ls", wzKey); if (*pwzData) { hr = ::StringCchCopyW(psf->wzMaxSize, countof(psf->wzMaxSize), pwzData); ExitOnFailure1(hr, "Failed to copy max size to filespec object: %ls", pwzData); } else { psf->wzMaxSize[0] = 0; } hr = WcaGetRecordFormattedString(hRec, sfsqGrowth, &pwzData); ExitOnFailure1(hr, "Failed to get SqlFileSpec.GrowthSize for filespec: %ls", wzKey); if (*pwzData) { hr = ::StringCchCopyW(psf->wzGrow, countof(psf->wzGrow), pwzData); ExitOnFailure1(hr, "Failed to copy growth size to filespec object: %ls", pwzData); } else { psf->wzGrow[0] = 0; } hr = S_OK; LExit: ReleaseStr(pwzData); return hr; }