static HRESULT AllocateRangeRequestHeader( __in DWORD64 dw64ResumeOffset, __in DWORD64 dw64ResourceLength, __deref_out_z LPWSTR* psczHeader ) { HRESULT hr = S_OK; // If the remaining length is less that 2GB we'll be able to ask for everything. DWORD64 dw64RemainingLength = dw64ResourceLength - dw64ResumeOffset; if (BURN_DOWNLOAD_ENGINE_TWO_GIGABYTES > dw64RemainingLength) { // If we have a resume offset, let's download everything from there. Otherwise, we'll // just get everything with no headers in the way. if (0 < dw64ResumeOffset) { hr = StrAllocFormatted(psczHeader, L"Range: bytes=%I64u-", dw64ResumeOffset); ExitOnFailure(hr, "Failed to add range read header."); } else { ReleaseNullStr(*psczHeader); } } else // we'll have to download in chunks. { hr = StrAllocFormatted(psczHeader, L"Range: bytes=%I64u-%I64u", dw64ResumeOffset, dw64ResumeOffset + dw64RemainingLength - 1); ExitOnFailure(hr, "Failed to add range read header."); } LExit: return hr; }
DAPIV_(HRESULT) BalLogError( __in HRESULT hrError, __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 error log string."); hr = StrAllocFormatted(&sczMessage, L"Error 0x%08x: %S", hrError, sczFormattedAnsi); ExitOnFailure(hr, "Failed to prepend error number to error log string."); hr = vpEngine->Log(BOOTSTRAPPER_LOG_LEVEL_ERROR, sczMessage); LExit: ReleaseStr(sczMessage); ReleaseStr(sczFormattedAnsi); return hr; }
HRESULT CpiBuildAccountName( LPCWSTR pwzDomain, LPCWSTR pwzName, LPWSTR* ppwzAccount ) { HRESULT hr = S_OK; WCHAR wzComputerName[MAX_COMPUTERNAME_LENGTH + 1]; ::ZeroMemory(wzComputerName, sizeof(wzComputerName)); // if domain is '.', get computer name if (0 == lstrcmpW(pwzDomain, L".")) { DWORD dwSize = countof(wzComputerName); if (!::GetComputerNameW(wzComputerName, &dwSize)) ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to get computer name"); } // build account name hr = StrAllocFormatted(ppwzAccount, L"%s\\%s", *wzComputerName ? wzComputerName : pwzDomain, pwzName); ExitOnFailure(hr, "Failed to build domain user name"); hr = S_OK; LExit: return hr; }
HRESULT CpiGetTempFileName( LPWSTR* ppwzTempFile ) { HRESULT hr = S_OK; // get temp path WCHAR wzTempPath[MAX_PATH]; DWORD dw = ::GetTempPathW(countof(wzTempPath), wzTempPath); if (countof(wzTempPath) <= dw) ExitOnFailure(hr = E_FAIL, "TEMP directory path too long"); // get unique number LARGE_INTEGER liCount; if (!::QueryPerformanceCounter(&liCount)) ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to query performance counter"); // create temp file name hr = StrAllocFormatted(ppwzTempFile, L"%sCPI%I64X.tmp", wzTempPath, liCount.QuadPart); ExitOnFailure(hr, "Failed to create temp file name string"); hr = S_OK; LExit: return hr; }
/******************************************************************* PipeCreateNameAndSecret - *******************************************************************/ extern "C" HRESULT PipeCreateNameAndSecret( __out_z LPWSTR *psczConnectionName, __out_z LPWSTR *psczSecret ) { HRESULT hr = S_OK; WCHAR wzGuid[GUID_STRING_LENGTH]; LPWSTR sczConnectionName = NULL; LPWSTR sczSecret = NULL; // Create the unique pipe name. hr = GuidFixedCreate(wzGuid); ExitOnRootFailure(hr, "Failed to create pipe guid."); hr = StrAllocFormatted(&sczConnectionName, L"BurnPipe.%s", wzGuid); ExitOnFailure(hr, "Failed to allocate pipe name."); // Create the unique client secret. hr = GuidFixedCreate(wzGuid); ExitOnRootFailure(hr, "Failed to create pipe secret."); hr = StrAllocString(&sczSecret, wzGuid, 0); ExitOnFailure(hr, "Failed to allocate pipe secret."); *psczConnectionName = sczConnectionName; sczConnectionName = NULL; *psczSecret = sczSecret; sczSecret = NULL; LExit: ReleaseStr(sczSecret); ReleaseStr(sczConnectionName); return hr; }
/******************************************************************* PipeLaunchChildProcess - Called from the per-user process to create the per-machine process and set up the communication pipe. *******************************************************************/ extern "C" HRESULT PipeLaunchChildProcess( __in_z LPCWSTR wzExecutablePath, __in BURN_PIPE_CONNECTION* pConnection, __in BOOL fElevate, __in_opt HWND hwndParent ) { HRESULT hr = S_OK; DWORD dwCurrentProcessId = ::GetCurrentProcessId(); LPWSTR sczParameters = NULL; OS_VERSION osVersion = OS_VERSION_UNKNOWN; DWORD dwServicePack = 0; LPCWSTR wzVerb = NULL; HANDLE hProcess = NULL; hr = StrAllocFormatted(&sczParameters, L"-q -%ls %ls %ls %u", BURN_COMMANDLINE_SWITCH_ELEVATED, pConnection->sczName, pConnection->sczSecret, dwCurrentProcessId); ExitOnFailure(hr, "Failed to allocate parameters for elevated process."); OsGetVersion(&osVersion, &dwServicePack); wzVerb = (OS_VERSION_VISTA > osVersion) || !fElevate ? L"open" : L"runas"; hr = ShelExec(wzExecutablePath, sczParameters, wzVerb, NULL, SW_HIDE, hwndParent, &hProcess); ExitOnFailure(hr, "Failed to launch elevated child process: %ls", wzExecutablePath); pConnection->dwProcessId = ::GetProcessId(hProcess); pConnection->hProcess = hProcess; hProcess = NULL; LExit: ReleaseHandle(hProcess); ReleaseStr(sczParameters); return hr; }
/******************************************************************** SqlSessionDropDatabase - removes a database from a server if it exists NOTE: pidbSession must be connected to the master database ********************************************************************/ extern "C" HRESULT DAPI SqlSessionDropDatabase( __in IDBCreateSession* pidbSession, __in_z LPCWSTR wzDatabase, __out_opt BSTR* pbstrErrorDescription ) { Assert(pidbSession && wzDatabase && *wzDatabase); HRESULT hr = S_OK; LPWSTR pwzQuery = NULL; LPWSTR pwzDatabaseEscaped = NULL; hr = SqlSessionDatabaseExists(pidbSession, wzDatabase, pbstrErrorDescription); ExitOnFailure1(hr, "failed to determine if exists, database: %ls", wzDatabase); hr = EscapeSqlIdentifier(wzDatabase, &pwzDatabaseEscaped); ExitOnFailure(hr, "failed to escape database string"); if (S_OK == hr) { hr = StrAllocFormatted(&pwzQuery, L"DROP DATABASE %s", pwzDatabaseEscaped); ExitOnFailure1(hr, "failed to allocate query to drop database: %ls", pwzDatabaseEscaped); hr = SqlSessionExecuteQuery(pidbSession, pwzQuery, NULL, NULL, pbstrErrorDescription); ExitOnFailure(hr, "Failed to drop database"); } LExit: ReleaseStr(pwzQuery); ReleaseStr(pwzDatabaseEscaped); return hr; }
extern "C" HRESULT DAPI LocAddString( __in WIX_LOCALIZATION* pWixLoc, __in_z LPCWSTR wzId, __in_z LPCWSTR wzLocString, __in BOOL bOverridable ) { HRESULT hr = S_OK; ++pWixLoc->cLocStrings; pWixLoc->rgLocStrings = static_cast<LOC_STRING*>(MemReAlloc(pWixLoc->rgLocStrings, sizeof(LOC_STRING) * pWixLoc->cLocStrings, TRUE)); ExitOnNull(pWixLoc->rgLocStrings, hr, E_OUTOFMEMORY, "Failed to reallocate memory for localization strings."); LOC_STRING* pLocString = pWixLoc->rgLocStrings + (pWixLoc->cLocStrings - 1); hr = StrAllocFormatted(&pLocString->wzId, L"#(loc.%s)", wzId); ExitOnFailure(hr, "Failed to set localization string Id."); hr = StrAllocString(&pLocString->wzText, wzLocString, 0); ExitOnFailure(hr, "Failed to set localization string Text."); pLocString->bOverridable = bOverridable; LExit: return hr; }
HRESULT ScaVirtualDirsUninstall7( __in SCA_VDIR7* psvdList ) { HRESULT hr = S_OK; SCA_VDIR7* psvd = psvdList; LPWSTR wzPath = NULL; while (psvd) { if (WcaIsUninstalling(psvd->isInstalled, psvd->isAction)) { //init path hr = StrAllocFormatted(&wzPath, L"/%s", psvd->wzVDirRoot); ExitOnFailure(hr, "Failed to create vdir path"); if (psvd->fHasApplication) { //delete Application hr = ScaWriteConfigID(IIS_APPLICATION); ExitOnFailure(hr, "Failed to write app ID "); hr = ScaWriteConfigID(IIS_DELETE); ExitOnFailure(hr, "Failed to write delete app ID "); #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") hr = ScaWriteConfigString(psvd->wzWebName); //site name key ExitOnFailure(hr, "Failed to write App site Name"); #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") hr = ScaWriteConfigString(wzPath); // App Path ExitOnFailure(hr, "Failed to write app path root "); hr = ScaWriteConfigString(L"NOP"); // App pool ExitOnFailure(hr, "Failed to write app path app pool "); } else { //delete VDir hr = ScaWriteConfigID(IIS_VDIR); ExitOnFailure(hr, "Failed to write vDir ID "); hr = ScaWriteConfigID(IIS_DELETE); #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") hr = ScaWriteConfigString(psvd->wzWebName); //site name key ExitOnFailure(hr, "Failed to write App site Name"); hr = ScaWriteConfigString(wzPath); // Vdir Path ExitOnFailure(hr, "Failed to write app vdir "); hr = ScaWriteConfigString(L"NOP"); // Phy Path ExitOnFailure(hr, "Failed to write vdir path"); } ExitOnFailure(hr, "Failed to remove VirtualDir '%ls' from config", psvd->wzKey); } psvd = psvd->psvdNext; } LExit: ReleaseStr(wzPath); return hr; }
HRESULT PipeLaunchParentProcess( __in_z LPCWSTR wzCommandLine, __in int nCmdShow, __in_z LPWSTR sczConnectionName, __in_z LPWSTR sczSecret, __in BOOL /*fDisableUnelevate*/ ) { HRESULT hr = S_OK; DWORD dwProcessId = 0; LPWSTR sczBurnPath = NULL; LPWSTR sczParameters = NULL; HANDLE hProcess = NULL; dwProcessId = ::GetCurrentProcessId(); hr = PathForCurrentProcess(&sczBurnPath, NULL); ExitOnFailure(hr, "Failed to get current process path."); hr = StrAllocFormatted(&sczParameters, L"-%ls %ls %ls %u %ls", BURN_COMMANDLINE_SWITCH_UNELEVATED, sczConnectionName, sczSecret, dwProcessId, wzCommandLine); ExitOnFailure(hr, "Failed to allocate parameters for unelevated process."); #ifdef ENABLE_UNELEVATE if (fDisableUnelevate) { hr = ProcExec(sczBurnPath, sczParameters, nCmdShow, &hProcess); ExitOnFailure1(hr, "Failed to launch parent process with unelevate disabled: %ls", sczBurnPath); } else { // Try to launch unelevated and if that fails for any reason, try launch our process normally (even though that may make it elevated). hr = ProcExecuteAsInteractiveUser(sczBurnPath, sczParameters, &hProcess); if (FAILED(hr)) { hr = ShelExecUnelevated(sczBurnPath, sczParameters, L"open", NULL, nCmdShow); if (FAILED(hr)) { hr = ShelExec(sczBurnPath, sczParameters, L"open", NULL, nCmdShow, NULL, NULL); ExitOnFailure1(hr, "Failed to launch parent process: %ls", sczBurnPath); } } } #else hr = ProcExec(sczBurnPath, sczParameters, nCmdShow, &hProcess); ExitOnFailure1(hr, "Failed to launch parent process with unelevate disabled: %ls", sczBurnPath); #endif LExit: ReleaseHandle(hProcess); ReleaseStr(sczParameters); ReleaseStr(sczBurnPath); return hr; }
/******************************************************************* PipeCreateNameAndSecret - *******************************************************************/ extern "C" HRESULT PipeCreateNameAndSecret( __out_z LPWSTR *psczConnectionName, __out_z LPWSTR *psczSecret ) { HRESULT hr = S_OK; RPC_STATUS rs = RPC_S_OK; UUID guid = { }; WCHAR wzGuid[39]; LPWSTR sczConnectionName = NULL; LPWSTR sczSecret = NULL; // Create the unique pipe name. rs = ::UuidCreate(&guid); hr = HRESULT_FROM_RPC(rs); ExitOnFailure(hr, "Failed to create pipe guid."); if (!::StringFromGUID2(guid, wzGuid, countof(wzGuid))) { hr = E_OUTOFMEMORY; ExitOnRootFailure(hr, "Failed to convert pipe guid into string."); } hr = StrAllocFormatted(&sczConnectionName, L"BurnPipe.%s", wzGuid); ExitOnFailure(hr, "Failed to allocate pipe name."); // Create the unique client secret. rs = ::UuidCreate(&guid); hr = HRESULT_FROM_RPC(rs); ExitOnRootFailure(hr, "Failed to create pipe guid."); if (!::StringFromGUID2(guid, wzGuid, countof(wzGuid))) { hr = E_OUTOFMEMORY; ExitOnRootFailure(hr, "Failed to convert pipe guid into string."); } hr = StrAllocString(&sczSecret, wzGuid, 0); ExitOnFailure(hr, "Failed to allocate pipe secret."); *psczConnectionName = sczConnectionName; sczConnectionName = NULL; *psczSecret = sczSecret; sczSecret = NULL; LExit: ReleaseStr(sczSecret); ReleaseStr(sczConnectionName); return hr; }
void CfgTest::SetApplication(LPCWSTR wzFileName, LPCWSTR wzFilePath) { HRESULT hr = S_OK; HKEY hk = NULL; LPWSTR sczFullPath = NULL; LPWSTR sczQuotedCommand = NULL; hr = StrAllocFormatted(&sczFullPath, L"%ls\\%ls\\shell\\open\\command", APPLICATIONS_REG_KEY, wzFileName); ExitOnFailure(hr, "Failed to format string to full shell\\open\\command path"); hr = RegCreate(HKEY_CURRENT_USER, sczFullPath, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &hk); ExitOnFailure1(hr, "Failed to create key: %ls", sczFullPath); hr = StrAllocFormatted(&sczQuotedCommand, L"\"%ls\" \"%%1\"", wzFilePath); ExitOnFailure(hr, "Failed to format quoted command string"); hr = RegWriteString(hk, NULL, sczQuotedCommand); ExitOnFailure(hr, "Failed to write quoted command to registry"); LExit: ReleaseRegKey(hk); ReleaseStr(sczFullPath); ReleaseStr(sczQuotedCommand); }
/******************************************************************** 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; }
/******************************************************************** SqlSessionDatabaseExists - determines if database exists NOTE: pidbSession must be connected to master database returns S_OK if database exist returns S_FALSE if database does not exist returns E_* on error ********************************************************************/ extern "C" HRESULT DAPI SqlSessionDatabaseExists( __in IDBCreateSession* pidbSession, __in_z LPCWSTR wzDatabase, __out_opt BSTR* pbstrErrorDescription ) { Assert(pidbSession && wzDatabase && *wzDatabase); HRESULT hr = S_OK; LPWSTR pwzQuery = NULL; IRowset* pirs = NULL; DBCOUNTITEM cRows = 0; HROW rghRows[1]; HROW* prow = rghRows; // // query to see if the database exists // hr = StrAllocFormatted(&pwzQuery, L"SELECT name FROM sysdatabases WHERE name='%s'", wzDatabase); ExitOnFailure(hr, "failed to allocate query string to ensure database exists"); hr = SqlSessionExecuteQuery(pidbSession, pwzQuery, &pirs, NULL, pbstrErrorDescription); ExitOnFailure(hr, "failed to get database list from 'master' database"); Assert(pirs); // // check to see if the database was returned // hr = pirs->GetNextRows(DB_NULL_HCHAPTER, 0, 1, &cRows, &prow); ExitOnFailure(hr, "failed to get row with database name"); // succeeded but no database if ((DB_S_ENDOFROWSET == hr) || (0 == cRows)) { hr = S_FALSE; } LExit: ReleaseObject(pirs); ReleaseStr(pwzQuery); return hr; }
DAPI_(HRESULT) JsonWriteNumber( __in JSON_WRITER* pWriter, __in DWORD dwValue ) { HRESULT hr = S_OK; LPWSTR sczValue = NULL; hr = StrAllocFormatted(&sczValue, L"%u", dwValue); ExitOnFailure(hr, "Failed to convert number to string."); hr = DoValue(pWriter, sczValue); ExitOnFailure(hr, "Failed to add number to JSON."); LExit: ReleaseStr(sczValue); return hr; }
DAPI_(HRESULT) JsonWriteObjectKey( __in JSON_WRITER* pWriter, __in_z LPCWSTR wzKey ) { HRESULT hr = S_OK; LPWSTR sczObjectKey = NULL; hr = StrAllocFormatted(&sczObjectKey, L"\"%ls\":", wzKey); ExitOnFailure(hr, "Failed to allocate JSON object key."); hr = DoKey(pWriter, sczObjectKey); ExitOnFailure(hr, "Failed to add object key to JSON."); LExit: ReleaseStr(sczObjectKey); return hr; }
static HRESULT ParseWxlString( __in IXMLDOMNode* pixn, __in DWORD dwIdx, __in WIX_LOCALIZATION* pWixLoc ) { HRESULT hr = S_OK; LOC_STRING* pLocString = NULL; BSTR bstrText = NULL; pLocString = pWixLoc->rgLocStrings + dwIdx; // Id hr = XmlGetAttribute(pixn, L"Id", &bstrText); ExitOnFailure(hr, "Failed to get Xml attribute Id in Wxl file."); hr = StrAllocFormatted(&pLocString->wzId, L"#(loc.%s)", bstrText); ExitOnFailure(hr, "Failed to duplicate Xml attribute Id in Wxl file."); ReleaseNullBSTR(bstrText); // Overrideable hr = XmlGetAttribute(pixn, L"Overridable", &bstrText); ExitOnFailure(hr, "Failed to get Xml attribute Overridable."); if (S_OK == hr) { pLocString->bOverridable = CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrText, -1, L"yes", -1); } ReleaseNullBSTR(bstrText); // Text hr = XmlGetText(pixn, &bstrText); ExitOnFailure(hr, "Failed to get Xml text in Wxl file."); hr = StrAllocString(&pLocString->wzText, bstrText, 0); ExitOnFailure(hr, "Failed to duplicate Xml text in Wxl file."); LExit: ReleaseBSTR(bstrText); return hr; }
static HRESULT GetNonSessionSpecificTempFolder( __deref_out_z LPWSTR* psczNonSessionTempFolder ) { HRESULT hr = S_OK; WCHAR wzTempFolder[MAX_PATH] = { }; DWORD cchTempFolder = 0; DWORD dwSessionId = 0; LPWSTR sczSessionId = 0; DWORD cchSessionId = 0; if (!::GetTempPathW(countof(wzTempFolder), wzTempFolder)) { ExitWithLastError(hr, "Failed to get temp folder."); } hr = ::StringCchLengthW(wzTempFolder, countof(wzTempFolder), reinterpret_cast<size_t*>(&cchTempFolder)); ExitOnFailure(hr, "Failed to get length of temp folder."); // If our session id is in the TEMP path then remove that part so we get the non-session // specific temporary folder. if (::ProcessIdToSessionId(::GetCurrentProcessId(), &dwSessionId)) { hr = StrAllocFormatted(&sczSessionId, L"%u\\", dwSessionId); ExitOnFailure(hr, "Failed to format session id as a string."); hr = ::StringCchLengthW(sczSessionId, STRSAFE_MAX_CCH, reinterpret_cast<size_t*>(&cchSessionId)); ExitOnFailure(hr, "Failed to get length of session id string."); if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzTempFolder + cchTempFolder - cchSessionId, cchSessionId, sczSessionId, cchSessionId)) { cchTempFolder -= cchSessionId; } } hr = StrAllocString(psczNonSessionTempFolder, wzTempFolder, cchTempFolder); ExitOnFailure(hr, "Failed to copy temp folder."); LExit: ReleaseStr(sczSessionId); return hr; }
static HRESULT CaScriptFileName( __in WCA_ACTION action, __in WCA_CASCRIPT script, __in BOOL fImpersonated, __in LPCWSTR wzScriptKey, __out LPWSTR* ppwzScriptName ) { HRESULT hr = S_OK; WCHAR wzTempPath[MAX_PATH]; LPWSTR pwzProductCode = NULL; WCHAR chInstallOrUninstall = action == WCA_ACTION_INSTALL ? L'i' : L'u'; WCHAR chScheduledOrRollback = script == WCA_CASCRIPT_SCHEDULED ? L's' : L'r'; WCHAR chUserOrMachine = fImpersonated ? L'u' : L'm'; if (fImpersonated) { if (!::GetTempPathW(countof(wzTempPath), wzTempPath)) { ExitWithLastError(hr, "Failed to get temp path."); } } else { if (!::GetWindowsDirectoryW(wzTempPath, countof(wzTempPath))) { ExitWithLastError(hr, "Failed to get windows path."); } hr = ::StringCchCatW(wzTempPath, countof(wzTempPath), L"\\Installer\\"); ExitOnFailure(hr, "Failed to concat Installer directory on windows path string."); } hr = WcaGetProperty(L"ProductCode", &pwzProductCode); ExitOnFailure(hr, "Failed to get ProductCode."); hr = StrAllocFormatted(ppwzScriptName, L"%swix%s.%s.%c%c%c", wzTempPath, pwzProductCode, wzScriptKey, chScheduledOrRollback, chUserOrMachine, chInstallOrUninstall); ExitOnFailure(hr, "Failed to allocate path to ca script."); LExit: ReleaseStr(pwzProductCode); return hr; }
/******************************************************************** SqlSessionCreateDatabase - creates a database on the server NOTE: pidbSession must be connected to the master database ********************************************************************/ extern "C" HRESULT DAPI SqlSessionCreateDatabase( __in IDBCreateSession* pidbSession, __in_z LPCWSTR wzDatabase, __in_opt const SQL_FILESPEC* psfDatabase, __in_opt const SQL_FILESPEC* psfLog, __out_opt BSTR* pbstrErrorDescription ) { HRESULT hr = S_OK; LPWSTR pwzDbFile = NULL; LPWSTR pwzLogFile = NULL; LPWSTR pwzQuery = NULL; LPWSTR pwzDatabaseEscaped = NULL; if (psfDatabase) { hr = FileSpecToString(psfDatabase, &pwzDbFile); ExitOnFailure(hr, "failed to convert db filespec to string"); } if (psfLog) { hr = FileSpecToString(psfLog, &pwzLogFile); ExitOnFailure(hr, "failed to convert log filespec to string"); } hr = EscapeSqlIdentifier(wzDatabase, &pwzDatabaseEscaped); ExitOnFailure(hr, "failed to escape database string"); hr = StrAllocFormatted(&pwzQuery, L"CREATE DATABASE %s %s%s %s%s", pwzDatabaseEscaped, pwzDbFile ? L"ON " : L"", pwzDbFile ? pwzDbFile : L"", pwzLogFile ? L"LOG ON " : L"", pwzLogFile ? pwzLogFile : L""); ExitOnFailure1(hr, "failed to allocate query to create database: %ls", pwzDatabaseEscaped); hr = SqlSessionExecuteQuery(pidbSession, pwzQuery, NULL, NULL, pbstrErrorDescription); ExitOnFailure2(hr, "failed to create database: %ls, Query: %ls", pwzDatabaseEscaped, pwzQuery); LExit: ReleaseStr(pwzQuery); ReleaseStr(pwzLogFile); ReleaseStr(pwzDbFile); ReleaseStr(pwzDatabaseEscaped); return hr; }
extern "C" HRESULT LoggingSetPackageVariable( __in BURN_PACKAGE* pPackage, __in_z_opt LPCWSTR wzSuffix, __in BOOL fRollback, __in BURN_LOGGING* pLog, __in BURN_VARIABLES* pVariables, __out_opt LPWSTR* psczLogPath ) { HRESULT hr = S_OK; LPWSTR sczLogPath = NULL; if (BURN_LOGGING_STATE_DISABLED == pLog->state) { if (psczLogPath) { *psczLogPath = NULL; } ExitFunction(); } if ((!fRollback && pPackage->sczLogPathVariable && *pPackage->sczLogPathVariable) || (fRollback && pPackage->sczRollbackLogPathVariable && *pPackage->sczRollbackLogPathVariable)) { hr = StrAllocFormatted(&sczLogPath, L"%ls%hs%ls_%03u_%ls%ls.%ls", pLog->sczPrefix, wzSuffix && *wzSuffix ? "_" : "", wzSuffix && *wzSuffix ? wzSuffix : L"", vdwPackageSequence, pPackage->sczId, fRollback ? L"_rollback" : L"", pLog->sczExtension); ExitOnFailure(hr, "Failed to allocate path for package log."); hr = VariableSetString(pVariables, fRollback ? pPackage->sczRollbackLogPathVariable : pPackage->sczLogPathVariable, sczLogPath, FALSE); ExitOnFailure(hr, "Failed to set log path into variable."); if (psczLogPath) { hr = StrAllocString(psczLogPath, sczLogPath, 0); ExitOnFailure(hr, "Failed to copy package log path."); } } LExit: ReleaseStr(sczLogPath); return hr; }
/******************************************************************** FileSpecToString *********************************************************************/ static HRESULT FileSpecToString( __in const SQL_FILESPEC* psf, __out LPWSTR* ppwz ) { Assert(psf && ppwz); HRESULT hr = S_OK; LPWSTR pwz = NULL; hr = StrAllocString(&pwz, L"(", 1024); ExitOnFailure(hr, "failed to allocate string for database file info"); ExitOnNull(*psf->wzName, hr, E_INVALIDARG, "logical name not specified in database file info"); ExitOnNull(*psf->wzFilename, hr, E_INVALIDARG, "filename not specified in database file info"); hr = StrAllocFormatted(&pwz, L"%sNAME=%s", pwz, psf->wzName); ExitOnFailure1(hr, "failed to format database file info name: %ls", psf->wzName); hr = StrAllocFormatted(&pwz, L"%s, FILENAME='%s'", pwz, psf->wzFilename); ExitOnFailure1(hr, "failed to format database file info filename: %ls", psf->wzFilename); if (0 != psf->wzSize[0]) { hr = StrAllocFormatted(&pwz, L"%s, SIZE=%s", pwz, psf->wzSize); ExitOnFailure1(hr, "failed to format database file info size: %s", psf->wzSize); } if (0 != psf->wzMaxSize[0]) { hr = StrAllocFormatted(&pwz, L"%s, MAXSIZE=%s", pwz, psf->wzMaxSize); ExitOnFailure1(hr, "failed to format database file info maxsize: %s", psf->wzMaxSize); } if (0 != psf->wzGrow[0]) { hr = StrAllocFormatted(&pwz, L"%s, FILEGROWTH=%s", pwz, psf->wzGrow); ExitOnFailure1(hr, "failed to format database file info growth: %s", psf->wzGrow); } hr = StrAllocFormatted(&pwz, L"%s)", pwz); ExitOnFailure(hr, "failed to allocate string for file spec"); *ppwz = pwz; pwz = NULL; // null here so it doesn't get freed below LExit: ReleaseStr(pwz); 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; }
static HRESULT EscapeSqlIdentifier( __in_z LPCWSTR wzIdentifier, __deref_out_z LPWSTR* ppwz ) { Assert(ppwz); HRESULT hr = S_OK; LPWSTR pwz = NULL; if (wzIdentifier == NULL) { //Just ignore a NULL identifier and clear out the result ReleaseNullStr(*ppwz); ExitFunction(); } int cchIdentifier = lstrlenW(wzIdentifier); //If an empty string or already escaped just copy if (cchIdentifier == 0 || (wzIdentifier[0] == '[' && wzIdentifier[cchIdentifier-1] == ']')) { hr = StrAllocString(&pwz, wzIdentifier, 0); ExitOnFailure1(hr, "failed to format database name: %ls", wzIdentifier); } else { //escape it hr = StrAllocFormatted(&pwz, L"[%s]", wzIdentifier); ExitOnFailure1(hr, "failed to format escaped database name: %ls", wzIdentifier); } *ppwz = pwz; pwz = NULL; // null here so it doesn't get freed below LExit: ReleaseStr(pwz); return hr; }
/**************************************************************************** StrCurrentTime - gets the current time in string format ****************************************************************************/ extern "C" HRESULT DAPI StrCurrentTime( __inout LPWSTR* ppwz, __in BOOL fGMT ) { SYSTEMTIME st; if (fGMT) { ::GetSystemTime(&st); } else { SYSTEMTIME stGMT; TIME_ZONE_INFORMATION tzi; ::GetTimeZoneInformation(&tzi); ::GetSystemTime(&stGMT); ::SystemTimeToTzSpecificLocalTime(&tzi, &stGMT, &st); } return StrAllocFormatted(ppwz, L"%02d:%02d:%02d", st.wHour, st.wMinute, st.wSecond); }
/******************************************************************* PipeLaunchChildProcess - Called from the per-user process to create the per-machine process and set up the communication pipe. *******************************************************************/ extern "C" HRESULT PipeLaunchChildProcess( __in_z LPCWSTR wzExecutablePath, __in BURN_PIPE_CONNECTION* pConnection, __in BOOL fElevate, __in_opt HWND hwndParent ) { HRESULT hr = S_OK; DWORD dwCurrentProcessId = ::GetCurrentProcessId(); LPWSTR sczParameters = NULL; OS_VERSION osVersion = OS_VERSION_UNKNOWN; DWORD dwServicePack = 0; LPCWSTR wzVerb = NULL; HANDLE hProcess = NULL; hr = StrAllocFormatted(&sczParameters, L"-q -%ls %ls %ls %u", BURN_COMMANDLINE_SWITCH_ELEVATED, pConnection->sczName, pConnection->sczSecret, dwCurrentProcessId); ExitOnFailure(hr, "Failed to allocate parameters for elevated process."); OsGetVersion(&osVersion, &dwServicePack); wzVerb = (OS_VERSION_VISTA > osVersion) || !fElevate ? L"open" : L"runas"; // Since ShellExecuteEx doesn't support passing inherited handles, don't bother with CoreAppendFileHandleSelfToCommandLine. // We could fallback to using ::DuplicateHandle to inject the file handle later if necessary. hr = ShelExec(wzExecutablePath, sczParameters, wzVerb, NULL, SW_SHOWNA, hwndParent, &hProcess); ExitOnFailure(hr, "Failed to launch elevated child process: %ls", wzExecutablePath); pConnection->dwProcessId = ::GetProcessId(hProcess); pConnection->hProcess = hProcess; hProcess = NULL; LExit: ReleaseHandle(hProcess); ReleaseStr(sczParameters); return hr; }
HRESULT ScaVirtualDirsInstall7( __in SCA_VDIR7* psvdList, __in SCA_APPPOOL * psapList ) { HRESULT hr = S_OK; SCA_VDIR7* psvd = psvdList; LPWSTR wzPath = NULL; WCHAR wzAppPoolName[MAX_PATH]; while (psvd) { if (WcaIsInstalling(psvd->isInstalled, psvd->isAction)) { // First write all applications, this is necessary since vdirs must be nested under the applications. if (psvd->fHasApplication) { //create the application for this vdir application hr = ScaWriteConfigID(IIS_APPLICATION); ExitOnFailure(hr, "Failed to write app ID"); hr = ScaWriteConfigID(IIS_CREATE); ExitOnFailure(hr, "Failed to write app action"); #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") hr = ScaWriteConfigString(psvd->wzWebName); //site name key ExitOnFailure(hr, "Failed to write app web key"); hr = StrAllocFormatted(&wzPath, L"/%s", psvd->wzVDirRoot); ExitOnFailure(hr, "Failed to create app path"); hr = ScaWriteConfigString(wzPath); // App Path ExitOnFailure(hr, "Failed to write app path root "); if (!*psvd->swapp.wzAppPool) { //This Application goes in default appPool hr = ScaWriteConfigString(L""); // App Pool } else { //get apppool from WebApplication #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") hr = ScaFindAppPool7(psvd->swapp.wzAppPool, wzAppPoolName, countof(wzAppPoolName), psapList); ExitOnFailure(hr, "Failed to read app pool from application"); hr = ScaWriteConfigString(wzAppPoolName); // App Pool ExitOnFailure(hr, "Failed to write appPool for vdir"); } } } psvd = psvd->psvdNext; } // Reset our linked list and write all the VDirs psvd = psvdList; while (psvd) { if (WcaIsInstalling(psvd->isInstalled, psvd->isAction)) { //create the Vdir hr = ScaWriteConfigID(IIS_VDIR); ExitOnFailure(hr, "Failed write VirDir ID") hr = ScaWriteConfigID(IIS_CREATE); ExitOnFailure(hr, "Failed write VirDir action") #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") hr = ScaWriteConfigString(psvd->wzWebName); //site name key ExitOnFailure(hr, "Failed write VirDir web name"); hr = StrAllocFormatted(&wzPath, L"/%s", psvd->wzVDirRoot); ExitOnFailure(hr, "Failed to create vdir path"); hr = ScaWriteConfigString(wzPath); //vdir path ExitOnFailure(hr, "Failed write VirDir path") #pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW") hr = ScaWriteConfigString(psvd->wzDirectory); //physical dir ExitOnFailure(hr, "Failed write VirDir dir"); if (psvd->fHasProperties) { ScaWriteWebDirProperties7(psvd->wzWebName, psvd->wzVDirRoot, &psvd->swp); ExitOnFailure(hr, "Failed to write directory properties for VirtualDir"); } if (psvd->fHasApplication) { hr = ScaWriteWebApplication7(psvd->wzWebName, psvd->wzVDirRoot, &psvd->swapp, psapList); ExitOnFailure(hr, "Failed to write application for VirtualDir"); } if (psvd->psmm) { hr = ScaWriteMimeMap7(psvd->wzWebName, psvd->wzVDirRoot, psvd->psmm); ExitOnFailure(hr, "Failed to write mimemap for VirtualDir"); } if (psvd->pshh) { hr = ScaWriteHttpHeader7(psvd->wzWebName, psvd->wzVDirRoot, psvd->pshh); ExitOnFailure(hr, "Failed to write custom HTTP headers for VirtualDir"); } if (psvd->pswe) { hr = ScaWriteWebError7(psvd->wzWebName, psvd->wzVDirRoot, psvd->pswe); ExitOnFailure(hr, "Failed to write custom web errors for VirtualDir"); } } psvd = psvd->psvdNext; } LExit: ReleaseStr(wzPath); return hr; }
/******************************************************************** SqlConnectDatabase - establishes a connection to a database NOTE: wzInstance is optional if fIntegratedAuth is set then wzUser and wzPassword are ignored ********************************************************************/ extern "C" HRESULT DAPI SqlConnectDatabase( __in_z LPCWSTR wzServer, __in_z LPCWSTR wzInstance, __in_z LPCWSTR wzDatabase, __in BOOL fIntegratedAuth, __in_z LPCWSTR wzUser, __in_z LPCWSTR wzPassword, __out IDBCreateSession** ppidbSession ) { Assert(wzServer && wzDatabase && *wzDatabase && ppidbSession); HRESULT hr = S_OK; LPWSTR pwzServerInstance = NULL; DBPROP rgdbpInit[4] = { }; DBPROPSET rgdbpsetInit[1] = { }; ULONG cProperties = 0; // if there is an instance if (wzInstance && *wzInstance) { hr = StrAllocFormatted(&pwzServerInstance, L"%s\\%s", wzServer, wzInstance); } else { hr = StrAllocString(&pwzServerInstance, wzServer, 0); } ExitOnFailure(hr, "failed to allocate memory for the server instance"); // server[\instance] rgdbpInit[cProperties].dwPropertyID = DBPROP_INIT_DATASOURCE; rgdbpInit[cProperties].dwOptions = DBPROPOPTIONS_REQUIRED; rgdbpInit[cProperties].colid = DB_NULLID; ::VariantInit(&rgdbpInit[cProperties].vValue); rgdbpInit[cProperties].vValue.vt = VT_BSTR; rgdbpInit[cProperties].vValue.bstrVal = ::SysAllocString(pwzServerInstance); ++cProperties; // database rgdbpInit[cProperties].dwPropertyID = DBPROP_INIT_CATALOG; rgdbpInit[cProperties].dwOptions = DBPROPOPTIONS_REQUIRED; rgdbpInit[cProperties].colid = DB_NULLID; ::VariantInit(&rgdbpInit[cProperties].vValue); rgdbpInit[cProperties].vValue.vt = VT_BSTR; rgdbpInit[cProperties].vValue.bstrVal= ::SysAllocString(wzDatabase); ++cProperties; if (fIntegratedAuth) { // username rgdbpInit[cProperties].dwPropertyID = DBPROP_AUTH_INTEGRATED; rgdbpInit[cProperties].dwOptions = DBPROPOPTIONS_REQUIRED; rgdbpInit[cProperties].colid = DB_NULLID; ::VariantInit(&rgdbpInit[cProperties].vValue); rgdbpInit[cProperties].vValue.vt = VT_BSTR; rgdbpInit[cProperties].vValue.bstrVal = ::SysAllocString(L"SSPI"); // default windows authentication ++cProperties; } else { // username rgdbpInit[cProperties].dwPropertyID = DBPROP_AUTH_USERID; rgdbpInit[cProperties].dwOptions = DBPROPOPTIONS_REQUIRED; rgdbpInit[cProperties].colid = DB_NULLID; ::VariantInit(&rgdbpInit[cProperties].vValue); rgdbpInit[cProperties].vValue.vt = VT_BSTR; rgdbpInit[cProperties].vValue.bstrVal = ::SysAllocString(wzUser); ++cProperties; // password rgdbpInit[cProperties].dwPropertyID = DBPROP_AUTH_PASSWORD; rgdbpInit[cProperties].dwOptions = DBPROPOPTIONS_REQUIRED; rgdbpInit[cProperties].colid = DB_NULLID; ::VariantInit(&rgdbpInit[cProperties].vValue); rgdbpInit[cProperties].vValue.vt = VT_BSTR; rgdbpInit[cProperties].vValue.bstrVal = ::SysAllocString(wzPassword); ++cProperties; } // put the properties into a set rgdbpsetInit[0].guidPropertySet = DBPROPSET_DBINIT; rgdbpsetInit[0].rgProperties = rgdbpInit; rgdbpsetInit[0].cProperties = cProperties; // obtain access to the SQL Native Client provider hr = InitializeDatabaseConnection(SQLNCLI_CLSID, "SQL Native Client", rgdbpsetInit, countof(rgdbpsetInit), ppidbSession); if (FAILED(hr)) { ExitTrace(hr, "Could not initialize SQL Native Client, falling back to SQL OLE DB..."); // try OLE DB but if that fails return original error failure HRESULT hr2 = InitializeDatabaseConnection(CLSID_SQLOLEDB, "SQL OLE DB", rgdbpsetInit, countof(rgdbpsetInit), ppidbSession); if (FAILED(hr2)) { ExitTrace(hr2, "Could not initialize SQL OLE DB either, giving up."); } else { hr = S_OK; } } LExit: for (; 0 < cProperties; cProperties--) { ::VariantClear(&rgdbpInit[cProperties - 1].vValue); } ReleaseStr(pwzServerInstance); return hr; }
static HRESULT CreateNetFxChainer( __in LPCWSTR wzSectionName, __in LPCWSTR wzEventName, __out NetFxChainer** ppChainer ) { HRESULT hr = S_OK; LPWSTR sczName = NULL; NetFxChainer* pChainer = NULL; pChainer = (NetFxChainer*)MemAlloc(sizeof(NetFxChainer), TRUE); ExitOnNull(pChainer, hr, E_OUTOFMEMORY, "Failed to allocate memory for NetFxChainer struct."); pChainer->hEventChaineeSend = ::CreateEvent(NULL, FALSE, FALSE, wzEventName); ExitOnNullWithLastError1(pChainer->hEventChaineeSend, hr, "Failed to create event: %ls", wzEventName); hr = StrAllocFormatted(&sczName, L"%ls_send", wzEventName); ExitOnFailure(hr, "failed to allocate memory for event name"); pChainer->hEventChainerSend = ::CreateEvent(NULL, FALSE, FALSE, sczName); ExitOnNullWithLastError1(pChainer->hEventChainerSend, hr, "Failed to create event: %ls", sczName); hr = StrAllocFormatted(&sczName, L"%ls_mutex", wzEventName); ExitOnFailure(hr, "failed to allocate memory for mutex name"); // Create the mutex, we initially own pChainer->hMutex = ::CreateMutex(NULL, TRUE, sczName); ExitOnNullWithLastError1(pChainer->hMutex, hr, "Failed to create mutex: %ls", sczName); pChainer->hSection = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, // security attributes PAGE_READWRITE, 0, // high-order DWORD of maximum size NETFXDATA_SIZE, // low-order DWORD of maximum size wzSectionName); ExitOnNullWithLastError1(pChainer->hSection, hr, "Failed to memory map cabinet file: %ls", wzSectionName); pChainer->pData = reinterpret_cast<NetFxDataStructure*>(::MapViewOfFile(pChainer->hSection, FILE_MAP_WRITE, 0, 0, // offsets 0 // map entire file )); ExitOnNullWithLastError1(pChainer->pData, hr, "Failed to MapViewOfFile for %ls.", wzSectionName); // Initialize the shared memory hr = ::StringCchCopyW(pChainer->pData->szEventName, countof(pChainer->pData->szEventName), wzEventName); ExitOnFailure(hr, "failed to copy event name to shared memory structure."); pChainer->pData->downloadFinished = false; pChainer->pData->downloadSoFar = 0; pChainer->pData->hrDownloadFinished = E_PENDING; pChainer->pData->downloadAbort = false; pChainer->pData->installFinished = false; pChainer->pData->installSoFar = 0; pChainer->pData->hrInstallFinished = E_PENDING; pChainer->pData->installAbort = false; pChainer->pData->hrInternalError = S_OK; pChainer->pData->version = NETFXDATA_VERSION; pChainer->pData->messageCode = 0; pChainer->pData->messageResponse = 0; pChainer->pData->messageDataLength = 0; // Done with initialization, allow others to access. ::ReleaseMutex(pChainer->hMutex); *ppChainer = pChainer; pChainer = NULL; LExit: ReleaseStr(sczName); if (pChainer) { // Something failed, release the mutex and destroy the object if (pChainer->hMutex) { ::ReleaseMutex(pChainer->hMutex); } DestroyNetFxChainer(pChainer); } return hr; }
extern "C" HRESULT NetFxRunChainer( __in LPCWSTR wzExecutablePath, __in LPCWSTR wzArguments, __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, __in LPVOID pvContext, __out DWORD* pdwExitCode ) { HRESULT hr = S_OK; DWORD er = 0; UUID guid = { }; WCHAR wzGuid[39]; RPC_STATUS rs = RPC_S_OK; LPWSTR sczEventName = NULL; LPWSTR sczSectionName = NULL; LPWSTR sczCommand = NULL; NetFxChainer* pNetfxChainer = NULL; STARTUPINFOW si = { }; PROCESS_INFORMATION pi = { }; HRESULT hrInternalError = 0; // Create the unique name suffix. rs = ::UuidCreate(&guid); hr = HRESULT_FROM_RPC(rs); ExitOnFailure(hr, "Failed to create netfx chainer guid."); if (!::StringFromGUID2(guid, wzGuid, countof(wzGuid))) { hr = E_OUTOFMEMORY; ExitOnRootFailure(hr, "Failed to convert netfx chainer guid into string."); } hr = StrAllocFormatted(&sczSectionName, L"NetFxSection.%ls", wzGuid); ExitOnFailure(hr, "Failed to allocate section name."); hr = StrAllocFormatted(&sczEventName, L"NetFxEvent.%ls", wzGuid); ExitOnFailure(hr, "Failed to allocate event name."); hr = CreateNetFxChainer(sczSectionName, sczEventName, &pNetfxChainer); ExitOnFailure(hr, "Failed to create netfx chainer."); hr = StrAllocFormatted(&sczCommand, L"%ls /pipe %ls", wzArguments, sczSectionName); ExitOnFailure(hr, "Failed to allocate netfx chainer arguments."); si.cb = sizeof(si); if (!::CreateProcessW(wzExecutablePath, sczCommand, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { ExitWithLastError1(hr, "Failed to CreateProcess on path: %ls", wzExecutablePath); } HANDLE handles[2] = { pi.hProcess, pNetfxChainer->hEventChaineeSend }; for (;;) { er = ::WaitForMultipleObjects(2, handles, FALSE, 100); if (WAIT_OBJECT_0 == er) { // Process has exited *pdwExitCode = NetFxGetResult(pNetfxChainer, &hrInternalError); if (E_PENDING == *pdwExitCode) { if (!::GetExitCodeProcess(pi.hProcess, pdwExitCode)) { ExitWithLastError(hr, "Failed to get netfx return code."); } } else if (FAILED(hrInternalError)) { // push internal error message OnNetFxError(pNetfxChainer, hrInternalError, pfnGenericMessageHandler, pvContext); ExitOnFailure(hr, "Failed to send internal error message from netfx chainer."); } break; } else if (WAIT_OBJECT_0 + 1 == er) { // Chainee has notified us of a change. hr = ProcessNetFxMessage(pNetfxChainer, pfnGenericMessageHandler, pvContext); ExitOnFailure(hr, "Failed to process netfx chainer message."); } else if (WAIT_FAILED == er) { ExitWithLastError(hr, "Failed to wait for netfx chainer process to complete"); } } LExit: ReleaseStr(sczSectionName); ReleaseStr(sczEventName); ReleaseStr(sczCommand); DestroyNetFxChainer(pNetfxChainer); ReleaseHandle(pi.hThread); ReleaseHandle(pi.hProcess); return hr; }