extern "C" HRESULT DAPI LocLoadFromResource( __in HMODULE hModule, __in_z LPCSTR szResource, __out WIX_LOCALIZATION** ppWixLoc ) { HRESULT hr = S_OK; LPVOID pvResource = NULL; DWORD cbResource = 0; LPWSTR sczXml = NULL; IXMLDOMDocument* pixd = NULL; hr = ResReadData(hModule, szResource, &pvResource, &cbResource); ExitOnFailure(hr, "Failed to read theme from resource."); hr = StrAllocStringAnsi(&sczXml, reinterpret_cast<LPCSTR>(pvResource), cbResource, CP_UTF8); ExitOnFailure(hr, "Failed to convert XML document data from UTF-8 to unicode string."); hr = XmlLoadDocument(sczXml, &pixd); ExitOnFailure(hr, "Failed to load theme resource as XML document."); hr = ParseWxl(pixd, ppWixLoc); ExitOnFailure(hr, "Failed to parse WXL."); LExit: ReleaseObject(pixd); ReleaseStr(sczXml); return hr; }
DAPIV_(HRESULT) BalLog( __in BOOTSTRAPPER_LOG_LEVEL level, __in_z __format_string LPCSTR szFormat, ... ) { HRESULT hr = S_OK; va_list args; LPSTR sczFormattedAnsi = NULL; LPWSTR sczMessage = NULL; if (!vpEngine) { hr = E_POINTER; ExitOnRootFailure(hr, "BalInitialize() must be called first."); } va_start(args, szFormat); hr = StrAnsiAllocFormattedArgs(&sczFormattedAnsi, szFormat, args); va_end(args); ExitOnFailure(hr, "Failed to format log string."); hr = StrAllocStringAnsi(&sczMessage, sczFormattedAnsi, 0, CP_UTF8); ExitOnFailure(hr, "Failed to convert log string to Unicode."); hr = vpEngine->Log(level, sczMessage); LExit: ReleaseStr(sczMessage); ReleaseStr(sczFormattedAnsi); return hr; }
static __callback INT_PTR FAR DIAMONDAPI CabExtractOpen(__in_z PSTR pszFile, __in int oflag, __in int pmode) { HRESULT hr = S_OK; INT_PTR pFile = -1; LPWSTR sczCabFile = NULL; // if FDI asks for some unusual mode (in low memory situation it could ask for a scratch file) fail if ((oflag != (/*_O_BINARY*/ 0x8000 | /*_O_RDONLY*/ 0x0000)) || (pmode != (_S_IREAD | _S_IWRITE))) { hr = E_OUTOFMEMORY; ExitOnFailure(hr, "FDI asked for a scratch file to be created, which is unsupported"); } hr = StrAllocStringAnsi(&sczCabFile, pszFile, 0, CP_UTF8); ExitOnFailure(hr, "Failed to convert UTF8 cab file name to wide character string"); pFile = reinterpret_cast<INT_PTR>(::CreateFileW(sczCabFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); if (INVALID_HANDLE_VALUE == reinterpret_cast<HANDLE>(pFile)) { ExitWithLastError1(hr, "failed to open file: %ls", sczCabFile); } if (vdw64EmbeddedOffset) { hr = CabExtractSeek(pFile, 0, 0); ExitOnFailure1(hr, "Failed to seek to embedded offset %I64d", vdw64EmbeddedOffset); } LExit: ReleaseStr(sczCabFile); return FAILED(hr) ? -1 : pFile; }
/******************************************************************** WcaCaScriptCreateKey() - creates a unique script key for this CustomAction. ********************************************************************/ extern "C" HRESULT WIXAPI WcaCaScriptCreateKey( __out LPWSTR* ppwzScriptKey ) { AssertSz(WcaIsInitialized(), "WcaInitialize() should have been called before calling this function."); HRESULT hr = S_OK; hr = StrAllocStringAnsi(ppwzScriptKey, WcaGetLogName(), 0, CP_ACP); ExitOnFailure(hr, "Failed to create script key."); LExit: 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 HandleOutput( __in BOOL fLogOutput, __in HANDLE hRead ) { BYTE *pBuffer = NULL; LPWSTR szLog = NULL; LPWSTR szTemp = NULL; LPWSTR pEnd = NULL; LPWSTR pNext = NULL; LPWSTR sczEscaped = NULL; LPSTR szWrite = NULL; DWORD dwBytes = OUTPUT_BUFFER; BOOL bFirst = TRUE; BOOL bUnicode = TRUE; HRESULT hr = S_OK; // Get buffer for output pBuffer = static_cast<BYTE *>(MemAlloc(OUTPUT_BUFFER, FALSE)); ExitOnNull(pBuffer, hr, E_OUTOFMEMORY, "Failed to allocate buffer for output."); while (0 != dwBytes) { ::ZeroMemory(pBuffer, OUTPUT_BUFFER); if (!::ReadFile(hRead, pBuffer, OUTPUT_BUFFER - 1, &dwBytes, NULL) && GetLastError() != ERROR_BROKEN_PIPE) { ExitOnLastError(hr, "Failed to read from handle."); } if (fLogOutput) { // Check for UNICODE or ANSI output if (bFirst) { if ((isgraph(pBuffer[0]) && isgraph(pBuffer[1])) || (isgraph(pBuffer[0]) && isspace(pBuffer[1])) || (isspace(pBuffer[0]) && isgraph(pBuffer[1])) || (isspace(pBuffer[0]) && isspace(pBuffer[1]))) { bUnicode = FALSE; } bFirst = FALSE; } // Keep track of output if (bUnicode) { hr = StrAllocConcat(&szLog, (LPCWSTR)pBuffer, 0); ExitOnFailure(hr, "Failed to concatenate output strings"); } else { hr = StrAllocStringAnsi(&szTemp, (LPCSTR)pBuffer, 0, CP_OEMCP); ExitOnFailure(hr, "Failed to allocate output string"); hr = StrAllocConcat(&szLog, szTemp, 0); ExitOnFailure(hr, "Failed to concatenate output strings"); } // Log each line of the output pNext = szLog; pEnd = wcschr(szLog, L'\r'); if (NULL == pEnd) { pEnd = wcschr(szLog, L'\n'); } while (pEnd && *pEnd) { // Find beginning of next line pEnd[0] = 0; ++pEnd; if ((pEnd[0] == L'\r') || (pEnd[0] == L'\n')) { ++pEnd; } // Log output hr = StrAllocString(&sczEscaped, pNext, 0); ExitOnFailure(hr, "Failed to allocate copy of string"); hr = StrReplaceStringAll(&sczEscaped, L"%", L"%%"); ExitOnFailure(hr, "Failed to escape percent signs in string"); hr = StrAnsiAllocString(&szWrite, sczEscaped, 0, CP_OEMCP); ExitOnFailure(hr, "Failed to convert output to ANSI"); WcaLog(LOGMSG_STANDARD, szWrite); // Next line pNext = pEnd; pEnd = wcschr(pNext, L'\r'); if (NULL == pEnd) { pEnd = wcschr(pNext, L'\n'); } } hr = StrAllocString(&szTemp, pNext, 0); ExitOnFailure(hr, "Failed to allocate string"); hr = StrAllocString(&szLog, szTemp, 0); ExitOnFailure(hr, "Failed to allocate string"); } } // Print any text that didn't end with a new line if (szLog && *szLog) { hr = StrReplaceStringAll(&szLog, L"%", L"%%"); ExitOnFailure(hr, "Failed to escape percent signs in string"); hr = StrAnsiAllocString(&szWrite, szLog, 0, CP_OEMCP); ExitOnFailure(hr, "Failed to convert output to ANSI"); WcaLog(LOGMSG_VERBOSE, szWrite); } LExit: ReleaseMem(pBuffer); ReleaseStr(szLog); ReleaseStr(szTemp); ReleaseStr(szWrite); ReleaseStr(sczEscaped); return hr; }