// The contents of psczOut may be sensitive, should keep encrypted and SecureZeroFree. DAPI_(HRESULT) BalFormatString( __in_z LPCWSTR wzFormat, __inout LPWSTR* psczOut ) { HRESULT hr = S_OK; DWORD cch = 0; if (!vpEngine) { hr = E_POINTER; ExitOnRootFailure(hr, "BalInitialize() must be called first."); } if (*psczOut) { hr = StrMaxLength(*psczOut, reinterpret_cast<DWORD_PTR*>(&cch)); ExitOnFailure(hr, "Failed to determine length of value."); } hr = vpEngine->FormatString(wzFormat, *psczOut, &cch); if (E_MOREDATA == hr) { ++cch; hr = StrAllocSecure(psczOut, cch); ExitOnFailure(hr, "Failed to allocate value."); hr = vpEngine->FormatString(wzFormat, *psczOut, &cch); } LExit: return hr; }
/******************************************************************** WcaGetRecordFormattedString() - gets formatted string filed from record ********************************************************************/ extern "C" HRESULT WIXAPI WcaGetRecordFormattedString( __in MSIHANDLE hRec, __in UINT uiField, __inout LPWSTR* ppwzData ) { if (!hRec || !ppwzData) { return E_INVALIDARG; } HRESULT hr = S_OK; UINT er; DWORD_PTR cch = 0; PMSIHANDLE hRecFormat; // get the format string hr = WcaGetRecordString(hRec, uiField, ppwzData); ExitOnFailure(hr, "failed to get string from record"); if (!**ppwzData) { ExitFunction(); } // hide the nulls '[~]' so we can get them back after formatting HideNulls(*ppwzData); // set up the format record hRecFormat = ::MsiCreateRecord(1); ExitOnNull(hRecFormat, hr, E_UNEXPECTED, "Failed to create record to format string"); hr = WcaSetRecordString(hRecFormat, 0, *ppwzData); ExitOnFailure(hr, "failed to set string to format record"); // format the string hr = StrMaxLength(*ppwzData, &cch); ExitOnFailure(hr, "failed to get max length of string"); er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecFormat, *ppwzData, (DWORD*)&cch); if (ERROR_MORE_DATA == er) { hr = StrAlloc(ppwzData, ++cch); ExitOnFailure(hr, "Failed to allocate memory for record string"); er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecFormat, *ppwzData, (DWORD*)&cch); } ExitOnWin32Error(er, hr, "Failed to format string"); // put the nulls back RevealNulls(*ppwzData); LExit: return hr; }
/******************************************************************** RegKeyEnum - enumerates a registry key. *********************************************************************/ extern "C" HRESULT DAPI RegKeyEnum( __in HKEY hk, __in DWORD dwIndex, __deref_out_z LPWSTR* psczKey ) { HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; DWORD cch = 0; if (psczKey && *psczKey) { hr = StrMaxLength(*psczKey, reinterpret_cast<DWORD_PTR*>(&cch)); ExitOnFailure(hr, "Failed to determine length of string."); } if (2 > cch) { cch = 2; hr = StrAlloc(psczKey, cch); ExitOnFailure(hr, "Failed to allocate string to minimum size."); } er = vpfnRegEnumKeyExW(hk, dwIndex, *psczKey, &cch, NULL, NULL, NULL, NULL); if (ERROR_MORE_DATA == er) { er = vpfnRegQueryInfoKeyW(hk, NULL, NULL, NULL, NULL, &cch, NULL, NULL, NULL, NULL, NULL, NULL); ExitOnWin32Error(er, hr, "Failed to get max size of subkey name under registry key."); ++cch; // add one because RegQueryInfoKeyW() returns the length of the subkeys without the null terminator. hr = StrAlloc(psczKey, cch); ExitOnFailure(hr, "Failed to allocate string bigger for enum registry key."); er = vpfnRegEnumKeyExW(hk, dwIndex, *psczKey, &cch, NULL, NULL, NULL, NULL); } else if (ERROR_NO_MORE_ITEMS == er) { ExitFunction1(hr = E_NOMOREITEMS); } ExitOnWin32Error(er, hr, "Failed to enum registry key."); // Always ensure the registry key name is null terminated. #pragma prefast(push) #pragma prefast(disable:26018) (*psczKey)[cch] = L'\0'; // note that cch will always be one less than the size of the buffer because that's how RegEnumKeyExW() works. #pragma prefast(pop) LExit: return hr; }
/******************************************************************** WcaGetFormattedString - gets a formatted string value from the active install ********************************************************************/ extern "C" HRESULT WIXAPI WcaGetFormattedString( __in_z LPCWSTR wzString, __out LPWSTR* ppwzData ) { if (!wzString || !*wzString || !ppwzData) { return E_INVALIDARG; } HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; PMSIHANDLE hRecord = ::MsiCreateRecord(1); DWORD_PTR cch = 0; er = ::MsiRecordSetStringW(hRecord, 0, wzString); ExitOnWin32Error1(er, hr, "Failed to set record field 0 with '%ls'", wzString); if (!*ppwzData) { WCHAR szEmpty[1] = L""; er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecord, szEmpty, (DWORD *)&cch); if (ERROR_MORE_DATA == er || ERROR_SUCCESS == er) { hr = StrAlloc(ppwzData, ++cch); } else { hr = HRESULT_FROM_WIN32(er); } ExitOnFailure1(hr, "Failed to allocate string for formatted string: '%ls'", wzString); } else { hr = StrMaxLength(*ppwzData, &cch); ExitOnFailure(hr, "Failed to get previous size of property data string"); } er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecord, *ppwzData, (DWORD *)&cch); if (ERROR_MORE_DATA == er) { hr = StrAlloc(ppwzData, ++cch); ExitOnFailure1(hr, "Failed to allocate string for formatted string: '%ls'", wzString); er = ::MsiFormatRecordW(WcaGetInstallHandle(), hRecord, *ppwzData, (DWORD *)&cch); } ExitOnWin32Error1(er, hr, "Failed to get formatted string: '%ls'", wzString); LExit: return hr; }
/******************************************************************** WcaGetTargetPath - gets the target path for a specified folder ********************************************************************/ extern "C" HRESULT WIXAPI WcaGetTargetPath( __in_z LPCWSTR wzFolder, __out LPWSTR* ppwzData ) { if (!wzFolder || !*wzFolder || !ppwzData) return E_INVALIDARG; HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; DWORD_PTR cch = 0; if (!*ppwzData) { WCHAR szEmpty[1] = L""; er = ::MsiGetTargetPathW(WcaGetInstallHandle(), wzFolder, szEmpty, (DWORD*)&cch); if (ERROR_MORE_DATA == er || ERROR_SUCCESS == er) { ++cch; //Add one for the null terminator hr = StrAlloc(ppwzData, cch); } else { hr = HRESULT_FROM_WIN32(er); } ExitOnFailure1(hr, "Failed to allocate string for target path of folder: '%ls'", wzFolder); } else { hr = StrMaxLength(*ppwzData, &cch); ExitOnFailure(hr, "Failed to get previous size of string"); } er = ::MsiGetTargetPathW(WcaGetInstallHandle(), wzFolder, *ppwzData, (DWORD*)&cch); if (ERROR_MORE_DATA == er) { ++cch; hr = StrAlloc(ppwzData, cch); ExitOnFailure1(hr, "Failed to allocate string for target path of folder: '%ls'", wzFolder); er = ::MsiGetTargetPathW(WcaGetInstallHandle(), wzFolder, *ppwzData, (DWORD*)&cch); } ExitOnWin32Error1(er, hr, "Failed to get target path for folder '%ls'", wzFolder); LExit: return hr; }
/******************************************************************** WcaGetProperty - gets a string property value from the active install ********************************************************************/ extern "C" HRESULT WIXAPI WcaGetProperty( __in_z LPCWSTR wzProperty, __inout LPWSTR* ppwzData ) { if (!wzProperty || !*wzProperty || !ppwzData) { return E_INVALIDARG; } HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; DWORD_PTR cch = 0; if (!*ppwzData) { WCHAR szEmpty[1] = L""; er = ::MsiGetPropertyW(WcaGetInstallHandle(), wzProperty, szEmpty, (DWORD *)&cch); if (ERROR_MORE_DATA == er || ERROR_SUCCESS == er) { hr = StrAlloc(ppwzData, ++cch); } else { hr = HRESULT_FROM_WIN32(er); } ExitOnFailure1(hr, "Failed to allocate string for Property '%ls'", wzProperty); } else { hr = StrMaxLength(*ppwzData, &cch); ExitOnFailure(hr, "Failed to get previous size of property data string."); } er = ::MsiGetPropertyW(WcaGetInstallHandle(), wzProperty, *ppwzData, (DWORD *)&cch); if (ERROR_MORE_DATA == er) { Assert(*ppwzData); hr = StrAlloc(ppwzData, ++cch); ExitOnFailure1(hr, "Failed to allocate string for Property '%ls'", wzProperty); er = ::MsiGetPropertyW(WcaGetInstallHandle(), wzProperty, *ppwzData, (DWORD *)&cch); } ExitOnWin32Error1(er, hr, "Failed to get data for property '%ls'", wzProperty); LExit: return hr; }
/******************************************************************** WcaGetRecordString() - gets a string field out of a record ********************************************************************/ extern "C" HRESULT WIXAPI WcaGetRecordString( __in MSIHANDLE hRec, __in UINT uiField, __inout LPWSTR* ppwzData ) { if (!hRec || !ppwzData) return E_INVALIDARG; HRESULT hr = S_OK; UINT er; DWORD_PTR cch = 0; if (!*ppwzData) { WCHAR szEmpty[1] = L""; er = ::MsiRecordGetStringW(hRec, uiField, szEmpty, (DWORD*)&cch); if (ERROR_MORE_DATA == er || ERROR_SUCCESS == er) { hr = StrAlloc(ppwzData, ++cch); } else { hr = HRESULT_FROM_WIN32(er); } ExitOnFailure(hr, "Failed to allocate memory for record string"); } else { hr = StrMaxLength(*ppwzData, &cch); ExitOnFailure(hr, "Failed to get previous size of string"); } er = ::MsiRecordGetStringW(hRec, uiField, *ppwzData, (DWORD*)&cch); if (ERROR_MORE_DATA == er) { hr = StrAlloc(ppwzData, ++cch); ExitOnFailure(hr, "Failed to allocate memory for record string"); er = ::MsiRecordGetStringW(hRec, uiField, *ppwzData, (DWORD*)&cch); } ExitOnWin32Error(er, hr, "Failed to get string from record"); LExit: return hr; }
//the contents of psczMessage may be sensitive, should keep encrypted and SecureZeroFree DAPI_(HRESULT) BalConditionEvaluate( __in BAL_CONDITION* pCondition, __in IBootstrapperEngine* pEngine, __out BOOL* pfResult, __out_z_opt LPWSTR* psczMessage ) { HRESULT hr = S_OK; DWORD_PTR cchMessage = 0; hr = pEngine->EvaluateCondition(pCondition->sczCondition, pfResult); ExitOnFailure(hr, "Failed to evaluate condition with bootstrapper engine."); if (psczMessage) { if (*psczMessage) { hr = StrMaxLength(*psczMessage, &cchMessage); ExitOnFailure(hr, "Failed to get length of message."); } hr = pEngine->FormatString(pCondition->sczMessage, *psczMessage, reinterpret_cast<DWORD*>(&cchMessage)); if (E_MOREDATA == hr) { ++cchMessage; hr = StrAllocSecure(psczMessage, cchMessage); ExitOnFailure(hr, "Failed to allocate string for condition's formatted message."); hr = pEngine->FormatString(pCondition->sczMessage, *psczMessage, reinterpret_cast<DWORD*>(&cchMessage)); } ExitOnFailure(hr, "Failed to format condition's message."); } LExit: return hr; }
DAPI_(HRESULT) PathExpand( __out LPWSTR *psczFullPath, __in_z LPCWSTR wzRelativePath, __in DWORD dwResolveFlags ) { Assert(wzRelativePath && *wzRelativePath); HRESULT hr = S_OK; DWORD cch = 0; LPWSTR sczExpandedPath = NULL; DWORD cchExpandedPath = 0; LPWSTR sczFullPath = NULL; // // First, expand any environment variables. // if (dwResolveFlags & PATH_EXPAND_ENVIRONMENT) { cchExpandedPath = PATH_GOOD_ENOUGH; hr = StrAlloc(&sczExpandedPath, cchExpandedPath); ExitOnFailure(hr, "Failed to allocate space for expanded path."); cch = ::ExpandEnvironmentStringsW(wzRelativePath, sczExpandedPath, cchExpandedPath); if (0 == cch) { ExitWithLastError1(hr, "Failed to expand environment variables in string: %ls", wzRelativePath); } else if (cchExpandedPath < cch) { cchExpandedPath = cch; hr = StrAlloc(&sczExpandedPath, cchExpandedPath); ExitOnFailure(hr, "Failed to re-allocate more space for expanded path."); cch = ::ExpandEnvironmentStringsW(wzRelativePath, sczExpandedPath, cchExpandedPath); if (0 == cch) { ExitWithLastError1(hr, "Failed to expand environment variables in string: %ls", wzRelativePath); } else if (cchExpandedPath < cch) { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); ExitOnFailure(hr, "Failed to allocate buffer for expanded path."); } } if (MAX_PATH < cch) { hr = PathPrefix(&sczExpandedPath); // ignore invald arg from path prefix because this may not be a complete path yet if (E_INVALIDARG == hr) { hr = S_OK; } ExitOnFailure(hr, "Failed to prefix long path after expanding environment variables."); hr = StrMaxLength(sczExpandedPath, reinterpret_cast<DWORD_PTR *>(&cchExpandedPath)); ExitOnFailure(hr, "Failed to get max length of expanded path."); } } // // Second, get the full path. // if (dwResolveFlags & PATH_EXPAND_FULLPATH) { LPWSTR wzFileName = NULL; LPCWSTR wzPath = sczExpandedPath ? sczExpandedPath : wzRelativePath; DWORD cchFullPath = PATH_GOOD_ENOUGH < cchExpandedPath ? cchExpandedPath : PATH_GOOD_ENOUGH; hr = StrAlloc(&sczFullPath, cchFullPath); ExitOnFailure(hr, "Failed to allocate space for full path."); cch = ::GetFullPathNameW(wzPath, cchFullPath, sczFullPath, &wzFileName); if (0 == cch) { ExitWithLastError1(hr, "Failed to get full path for string: %ls", wzPath); } else if (cchFullPath < cch) { cchFullPath = cch < MAX_PATH ? cch : cch + 7; // ensure space for "\\?\UNC" prefix if needed hr = StrAlloc(&sczFullPath, cchFullPath); ExitOnFailure(hr, "Failed to re-allocate more space for full path."); cch = ::GetFullPathNameW(wzPath, cchFullPath, sczFullPath, &wzFileName); if (0 == cch) { ExitWithLastError1(hr, "Failed to get full path for string: %ls", wzPath); } else if (cchFullPath < cch) { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); ExitOnFailure(hr, "Failed to allocate buffer for full path."); } } if (MAX_PATH < cch) { hr = PathPrefix(&sczFullPath); ExitOnFailure(hr, "Failed to prefix long path after expanding."); } } else { sczFullPath = sczExpandedPath; sczExpandedPath = NULL; } hr = StrAllocString(psczFullPath, sczFullPath? sczFullPath : wzRelativePath, 0); ExitOnFailure(hr, "Failed to copy relative path into full path."); LExit: ReleaseStr(sczFullPath); ReleaseStr(sczExpandedPath); return hr; }