void CfgTest::SetARP(LPCWSTR wzKeyName, LPCWSTR wzDisplayName, LPCWSTR wzInstallLocation, LPCWSTR wzUninstallString)
    {
        HRESULT hr = S_OK;
        HKEY hkArp = NULL;
        HKEY hkNew = NULL;

        hr = RegOpen(HKEY_CURRENT_USER, ARP_REG_KEY, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &hkArp);
        ExitOnFailure1(hr, "Failed to open fake ARP regkey: %ls", ARP_REG_KEY);

        hr = RegDelete(hkArp, wzKeyName, REG_KEY_32BIT, TRUE);
        if (E_FILENOTFOUND == hr)
        {
            hr = S_OK;
        }
        ExitOnFailure1(hr, "Failed to delete subkey: %ls", wzKeyName);

        if (NULL != wzDisplayName)
        {
            hr = RegCreate(hkArp, wzKeyName, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &hkNew);
            ExitOnFailure1(hr, "Failed to create subkey: %ls", wzKeyName);

            hr = RegWriteString(hkNew, L"DisplayName", wzDisplayName);
            ExitOnFailure(hr, "Failed to write DisplayName to registry");

            hr = RegWriteString(hkNew, L"UninstallString", wzUninstallString);
            ExitOnFailure(hr, "Failed to write UninstallString to registry");

            hr = RegWriteString(hkNew, L"InstallLocation", wzInstallLocation);
            ExitOnFailure(hr, "Failed to write InstallLocation to registry");
        }

    LExit:
        ReleaseRegKey(hkArp);
        ReleaseRegKey(hkNew);
    }
Example #2
0
extern "C" HRESULT DAPI PolcReadNumber(
    __in_z LPCWSTR wzPolicyPath,
    __in_z LPCWSTR wzPolicyName,
    __in DWORD dwDefault,
    __out DWORD* pdw
    )
{
    HRESULT hr = S_OK;
    HKEY hk = NULL;

    hr = OpenPolicyKey(wzPolicyPath, &hk);
    if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr)
    {
        ExitFunction1(hr = S_FALSE);
    }
    ExitOnFailure1(hr, "Failed to open policy key: %ls", wzPolicyPath);

    hr = RegReadNumber(hk, wzPolicyName, pdw);
    if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr)
    {
        ExitFunction1(hr = S_FALSE);
    }
    ExitOnFailure2(hr, "Failed to open policy key: %ls, name: %ls", wzPolicyPath, wzPolicyName);

LExit:
    ReleaseRegKey(hk);

    if (S_FALSE == hr || FAILED(hr))
    {
        *pdw = dwDefault;
    }

    return hr;
}
Example #3
0
static void CheckLoggingPolicy(
    __out DWORD *pdwAttributes
    )
{
    HRESULT hr = S_OK;
    HKEY hk = NULL;
    LPWSTR sczLoggingPolicy = NULL;

    hr = RegOpen(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Policies\\Microsoft\\Windows\\Installer", KEY_READ, &hk);
    if (SUCCEEDED(hr))
    {
        hr = RegReadString(hk, L"Logging", &sczLoggingPolicy);
        if (SUCCEEDED(hr))
        {
            LPCWSTR wz = sczLoggingPolicy;
            while (*wz)
            {
                if (L'v' == *wz || L'V' == *wz)
                {
                    *pdwAttributes |= BURN_LOGGING_ATTRIBUTE_VERBOSE;
                }
                else if (L'x' == *wz || L'X' == *wz)
                {
                    *pdwAttributes |= BURN_LOGGING_ATTRIBUTE_EXTRADEBUG;
                }

                ++wz;
            }
        }
    }

    ReleaseStr(sczLoggingPolicy);
    ReleaseRegKey(hk);
}
    void CfgTest::ExpectNoKey(HKEY hk, LPCWSTR wzKeyName)
    {
        HRESULT hr = S_OK;
        HKEY hkSub = NULL;

        hr = RegOpen(hk, wzKeyName, KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_WOW64_32KEY, &hkSub);
        if (E_FILENOTFOUND != hr)
        {
            hr = E_FAIL;
            ExitOnFailure1(hr, "Regkey should not exist, but it does: %ls", wzKeyName);
        }

    LExit:
        ReleaseRegKey(hkSub);
    }
    void CfgTest::TestInitialize()
    {
        HRESULT hr = S_OK;
        HKEY hk = NULL;

        hr = RegInitialize();
        ExitOnFailure(hr, "Failed to initialize regutil");

        // Override Arp regkey path
        hr = RegDelete(HKEY_CURRENT_USER, ARP_REG_KEY, REG_KEY_32BIT, TRUE);
        if (E_FILENOTFOUND == hr)
        {
            hr = S_OK;
        }
        ExitOnFailure1(hr, "Failed to delete fake ARP regkey: %ls", ARP_REG_KEY);

        hr = RegCreate(HKEY_CURRENT_USER, ARP_REG_KEY, REG_KEY_32BIT, &hk);
        ExitOnFailure1(hr, "Failed to create fake ARP regkey: %ls", ARP_REG_KEY);

        hr = TestHookOverrideArpPath(ARP_REG_KEY);
        ExitOnFailure(hr, "Failed to override ARP path for test");

        // Override Applications regkey path
        hr = RegDelete(HKEY_CURRENT_USER, APPLICATIONS_REG_KEY, REG_KEY_32BIT, TRUE);
        if (E_FILENOTFOUND == hr)
        {
            hr = S_OK;
        }
        ExitOnFailure1(hr, "Failed to delete fake Applications regkey: %ls", APPLICATIONS_REG_KEY);

        hr = RegCreate(HKEY_CURRENT_USER, APPLICATIONS_REG_KEY, REG_KEY_32BIT, &hk);
        ExitOnFailure1(hr, "Failed to create fake Applications regkey: %ls", APPLICATIONS_REG_KEY);

        hr = TestHookOverrideApplicationsPath(APPLICATIONS_REG_KEY);
        ExitOnFailure(hr, "Failed to override Applications path for test");

        RedirectDatabases();

    LExit:
        ReleaseRegKey(hk);
    }
Example #6
0
extern "C" HRESULT DAPI PolcReadString(
    __in_z LPCWSTR wzPolicyPath,
    __in_z LPCWSTR wzPolicyName,
    __in_z_opt LPCWSTR wzDefault,
    __deref_out_z LPWSTR* pscz
    )
{
    HRESULT hr = S_OK;
    HKEY hk = NULL;

    hr = OpenPolicyKey(wzPolicyPath, &hk);
    if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr)
    {
        ExitFunction1(hr = S_FALSE);
    }
    ExitOnFailure1(hr, "Failed to open policy key: %ls", wzPolicyPath);

    hr = RegReadString(hk, wzPolicyName, pscz);
    if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr)
    {
        ExitFunction1(hr = S_FALSE);
    }
    ExitOnFailure2(hr, "Failed to open policy key: %ls, name: %ls", wzPolicyPath, wzPolicyName);

LExit:
    ReleaseRegKey(hk);

    if (S_FALSE == hr || FAILED(hr))
    {
        if (NULL == wzDefault)
        {
            ReleaseNullStr(*pscz);
        }
        else
        {
            hr = StrAllocString(pscz, wzDefault, 0);
        }
    }

    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);
    }
Example #8
0
/********************************************************************
 RegDelete - deletes a registry key (and optionally it's whole tree).

*********************************************************************/
extern "C" HRESULT DAPI RegDelete(
    __in HKEY hkRoot,
    __in_z LPCWSTR wzSubKey,
    __in REG_KEY_BITNESS kbKeyBitness,
    __in BOOL fDeleteTree
    )
{
    HRESULT hr = S_OK;
    DWORD er = ERROR_SUCCESS;
    LPWSTR pszEnumeratedSubKey = NULL;
    LPWSTR pszRecursiveSubKey = NULL;
    HKEY hkKey = NULL;
    REGSAM samDesired = 0;

    if (fDeleteTree)
    {
        hr = RegOpen(hkRoot, wzSubKey, KEY_READ, &hkKey);
        if (E_FILENOTFOUND == hr)
        {
            ExitFunction1(hr = S_OK);
        }
        ExitOnFailure1(hr, "Failed to open this key for enumerating subkeys", wzSubKey);

        // Yes, keep enumerating the 0th item, because we're deleting it every time
        while (E_NOMOREITEMS != (hr = RegKeyEnum(hkKey, 0, &pszEnumeratedSubKey)))
        {
            ExitOnFailure(hr, "Failed to enumerate key 0");
            
            hr = PathConcat(wzSubKey, pszEnumeratedSubKey, &pszRecursiveSubKey);
            ExitOnFailure2(hr, "Failed to concatenate paths while recursively deleting subkeys. Path1: %ls, Path2: %ls", wzSubKey, pszEnumeratedSubKey);

            hr = RegDelete(hkRoot, pszRecursiveSubKey, kbKeyBitness, fDeleteTree);
            ExitOnFailure1(hr, "Failed to recursively delete subkey: %ls", pszRecursiveSubKey);
        }

        hr = S_OK;
    }

    if (!vfRegInitialized && REG_KEY_DEFAULT != kbKeyBitness)
    {
        hr = E_INVALIDARG;
        ExitOnFailure(hr, "RegInitialize must be called first in order to RegDelete() a key with non-default bit attributes!");
    }

    switch (kbKeyBitness)
    {
    case REG_KEY_32BIT:
        samDesired = KEY_WOW64_32KEY;
        break;
    case REG_KEY_64BIT:
        samDesired = KEY_WOW64_64KEY;
        break;
    case REG_KEY_DEFAULT:
        // Nothing to do
        break;
    }

    if (NULL != vpfnRegDeleteKeyExW)
    {
        er = vpfnRegDeleteKeyExW(hkRoot, wzSubKey, samDesired, 0);
        if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er))
        {
            ExitFunction1(hr = E_FILENOTFOUND);
        }
        ExitOnWin32Error(er, hr, "Failed to delete registry key (ex).");
    }
    else
    {
        er = vpfnRegDeleteKeyW(hkRoot, wzSubKey);
        if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er))
        {
            ExitFunction1(hr = E_FILENOTFOUND);
        }
        ExitOnWin32Error(er, hr, "Failed to delete registry key.");
    }

LExit:
    ReleaseRegKey(hkKey);
    ReleaseStr(pszEnumeratedSubKey);
    ReleaseStr(pszRecursiveSubKey);

    return hr;
}
Example #9
0
extern "C" HRESULT RegDefaultWriteValue(
    __in LEGACY_PRODUCT *pProduct,
    __in_z LPCWSTR wzName,
    __in const CONFIG_VALUE *pcvValue,
    __out BOOL *pfHandled
    )
{
    HRESULT hr = S_OK;
    LPWSTR sczValue = NULL;
    LPWSTR sczRegKey = NULL;
    LPWSTR sczRegValueName = NULL;
    BYTE *pbBuffer = NULL;
    SIZE_T cbBuffer = 0;
    BOOL fReleaseBuffer = FALSE;
    DWORD dwRoot = DWORD_MAX;
    HKEY hk = NULL;

    hr = MapCfgNameToRegValue(pProduct, wzName, &dwRoot, &sczRegKey, &sczRegValueName);
    if (E_INVALIDARG == hr)
    {
        *pfHandled = FALSE;
        // Not a regkey, so just ignore
        ExitFunction1(hr = S_OK);
    }
    ExitOnFailure(hr, "Failed to convert value name to registry information");
    *pfHandled = TRUE;

    hr = RegOpen(ManifestConvertToRootKey(dwRoot), sczRegKey, KEY_SET_VALUE, &hk);
    if (E_FILENOTFOUND == hr)
    {
        hr = S_OK;

        // The key doesn't exist, so no need to proceed with deleting the value
        if (VALUE_DELETED == pcvValue->cvType)
        {
            ExitFunction1(hr = S_OK);
        }
        hr = RegCreate(ManifestConvertToRootKey(dwRoot), sczRegKey, KEY_SET_VALUE, &hk);
        ExitOnFailure(hr, "Failed to create regkey: %ls", sczRegKey);
    }
    ExitOnFailure(hr, "Failed to open regkey: %ls", sczRegKey);

    switch (pcvValue->cvType)
    {
    case VALUE_DELETED:
        hr = RegWriteString(hk, sczRegValueName, NULL);
        ExitOnFailure(hr, "Failed to delete existing value");
        break;

    case VALUE_BLOB:
        switch (pcvValue->blob.cbType)
        {
        case CFG_BLOB_POINTER:
            pbBuffer = const_cast<BYTE *>(pcvValue->blob.pointer.pbValue);
            cbBuffer = pcvValue->blob.cbValue;
            break;
        case CFG_BLOB_DB_STREAM:
            fReleaseBuffer = TRUE;
            hr = StreamRead(pcvValue->blob.dbstream.pcdb, pcvValue->blob.dbstream.dwContentID, NULL, &pbBuffer, &cbBuffer);
            ExitOnFailure(hr, "Failed to read stream from database while writing binary to the registry");
            break;
        default:
            hr = E_INVALIDARG;
            ExitOnFailure(hr, "Invalid blob type encountered");
            break;
        }
        hr = RegWriteBinary(hk, sczRegValueName, pbBuffer, cbBuffer);
        ExitOnFailure(hr, "Failed to write binary value to registry");
        break;

    case VALUE_STRING:
        hr = RegWriteString(hk, sczRegValueName, pcvValue->string.sczValue);
        ExitOnFailure(hr, "Failed to write string to registry");
        break;

    case VALUE_DWORD:
        hr = RegWriteNumber(hk, sczRegValueName, pcvValue->dword.dwValue);
        ExitOnFailure(hr, "Failed to write dword to registry");
        break;

    case VALUE_QWORD:
        hr = RegWriteQword(hk, sczRegValueName, pcvValue->qword.qwValue);
        ExitOnFailure(hr, "Failed to write qword to registry");
        break;

    default:
        ExitFunction1(hr = E_INVALIDARG);
    }

LExit:
    ReleaseRegKey(hk);
    ReleaseStr(sczValue);
    ReleaseStr(sczRegKey);
    ReleaseStr(sczRegValueName);
    if (fReleaseBuffer)
    {
        ReleaseMem(pbBuffer);
    }

    return hr;
}
Example #10
0
static HRESULT DeleteEmptyRegistryKeyChildren(
    __in DWORD dwRoot,
    __in_z LPCWSTR wzSubKey
    )
{
    HRESULT hr = S_OK;
    HKEY hkKey = NULL;
    DWORD dwIndex = 0;
    BOOL fNoValues = FALSE;
    LPWSTR sczValueName = NULL;
    LPWSTR sczSubkeyName = NULL;
    LPWSTR sczSubkeyPath = NULL;
    DWORD dwSubKeyPathLen = 0;

    hr = RegOpen(ManifestConvertToRootKey(dwRoot), wzSubKey, KEY_READ, &hkKey);
    if (E_FILENOTFOUND == hr)
    {
        ExitFunction1(hr = S_OK);
    }
    ExitOnFailure(hr, "Failed to open regkey: %ls", wzSubKey);

    if (E_NOMOREITEMS == RegValueEnum(hkKey, dwIndex, &sczValueName, NULL))
    {
        fNoValues = TRUE;
    }

    // Recurse and handle subkeys as well
    dwIndex = 0;
    while (E_NOMOREITEMS != (hr = RegKeyEnum(hkKey, dwIndex, &sczSubkeyName)))
    {
        ExitOnFailure(hr, "Failed to enumerate key %u", dwIndex);

        hr = StrAllocString(&sczSubkeyPath, wzSubKey, 0);
        ExitOnFailure(hr, "Failed to allocate copy of subkey name");

        dwSubKeyPathLen = lstrlenW(sczSubkeyPath);

        if (0 == dwSubKeyPathLen)
        {
            hr = E_INVALIDARG;
            ExitOnFailure(hr, "Encountered empty keyname while enumerating subkeys under key: %ls", wzSubKey);
        }
        else if (L'\\' != sczSubkeyPath[dwSubKeyPathLen - 1])
        {
            hr = StrAllocConcat(&sczSubkeyPath, L"\\", 1);
            ExitOnFailure(hr, "Failed to concatenate backslash to copy of regkey name");
        }

        hr = StrAllocConcat(&sczSubkeyPath, sczSubkeyName, 0);
        ExitOnFailure(hr, "Failed to concatenate subkey name to subkey path");

        hr = DeleteEmptyRegistryKeyChildren(dwRoot, sczSubkeyPath);
        // Increment and ignore the error if we didn't delete the subkey
        if (HRESULT_FROM_WIN32(ERROR_DIR_NOT_EMPTY) == hr)
        {
            ++dwIndex;
            hr = S_OK;
        }
        ExitOnFailure(hr, "Failed to read regkey and write settings for root: %u, subkey: %ls", dwRoot, sczSubkeyPath);
    }

    // If there are no keys and no values under it, delete it
    if (fNoValues && 0 == dwIndex)
    {
        hr = RegDelete(ManifestConvertToRootKey(dwRoot), wzSubKey, REG_KEY_DEFAULT, FALSE);
        ExitOnFailure(hr, "Failed to delete registry key at root: %u, subkey: %ls", dwRoot, wzSubKey);

        ExitFunction1(hr = S_OK);
    }
    else
    {
        ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_DIR_NOT_EMPTY));
    }

LExit:
    ReleaseRegKey(hkKey);
    ReleaseStr(sczValueName);
    ReleaseStr(sczSubkeyName);
    ReleaseStr(sczSubkeyPath);

    return hr;
}
Example #11
0
static HRESULT ReadRegKeyWriteLegacyDb(
    __in CFGDB_STRUCT *pcdb,
    __in LEGACY_SYNC_PRODUCT_SESSION *pSyncProductSession,
    __in LEGACY_REGISTRY_KEY *pRegKey,
    __in_z LPCWSTR wzSubKey
    )
{
    HRESULT hr = S_OK;
    HKEY hkKey = NULL;
    DWORD dwType = 0;
    DWORD dwIndex = 0;
    LPWSTR sczValueName = NULL;
    LPWSTR sczSubkeyName = NULL;
    LPWSTR sczSubkeyPath = NULL;

    hr = RegOpen(ManifestConvertToRootKey(pRegKey->dwRoot), wzSubKey, KEY_READ, &hkKey);
    if (E_FILENOTFOUND == hr)
    {
        ExitFunction1(hr = S_OK);
    }
    ExitOnFailure(hr, "Failed to open regkey: %ls", wzSubKey);

    dwIndex = 0;
    while (E_NOMOREITEMS != (hr = RegValueEnum(hkKey, dwIndex, &sczValueName, &dwType)))
    {
        ExitOnFailure(hr, "Failed to enumerate value %u", dwIndex);

        hr = ReadRegValueWriteLegacyDb(pcdb, pSyncProductSession, pRegKey, hkKey, wzSubKey, sczValueName, dwType);
        ExitOnFailure(hr, "Failed to write registry value setting: %ls", sczValueName);

        ++dwIndex;
    }

    // Recurse and handle subkeys as well
    dwIndex = 0;
    while (E_NOMOREITEMS != (hr = RegKeyEnum(hkKey, dwIndex, &sczSubkeyName)))
    {
        ExitOnFailure(hr, "Failed to enumerate key %u", dwIndex);

        hr = StrAllocString(&sczSubkeyPath, wzSubKey, 0);
        ExitOnFailure(hr, "Failed to allocate copy of subkey name");

        hr = PathBackslashTerminate(&sczSubkeyPath);
        ExitOnFailure(hr, "Failed to ensure path is terminated with a backslash");

        hr = StrAllocConcat(&sczSubkeyPath, sczSubkeyName, 0);
        ExitOnFailure(hr, "Failed to concatenate subkey name to subkey path");

        hr = ReadRegKeyWriteLegacyDb(pcdb, pSyncProductSession, pRegKey, sczSubkeyPath);
        ExitOnFailure(hr, "Failed to read regkey and write settings for root: %u, subkey: %ls", pRegKey->dwRoot, sczSubkeyPath);

        ++dwIndex;
    }

    if (E_NOMOREITEMS == hr)
    {
        hr = S_OK;
    }

LExit:
    ReleaseRegKey(hkKey);
    ReleaseStr(sczValueName);
    ReleaseStr(sczSubkeyName);
    ReleaseStr(sczSubkeyPath);

    return hr;
}
Example #12
0
/*******************************************************************
Dutil_AssertMsg

*******************************************************************/
extern "C" void DAPI Dutil_AssertMsg(
    __in_z LPCSTR szMessage
    )
{
    static BOOL fInAssert = FALSE; // TODO: make this thread safe (this is a cheap hack to prevent re-entrant Asserts)

    HRESULT hr = S_OK;
    DWORD er = ERROR_SUCCESS;

    int id = IDRETRY;
    HKEY hkDebug = NULL;
    HANDLE hAssertFile = INVALID_HANDLE_VALUE;
    char szPath[MAX_PATH] = { };
    DWORD cch = 0;

    if (fInAssert)
    {
        return;
    }
    fInAssert = TRUE;

    char szMsg[DUTIL_STRING_BUFFER];
    hr = ::StringCchCopyA(szMsg, countof(szMsg), szMessage);
    ExitOnFailure(hr, "failed to copy message while building assert message");

    if (Dutil_pfnDisplayAssert)
    {
        // call custom function to display the assert string
        if (!Dutil_pfnDisplayAssert(szMsg))
        {
            ExitFunction();
        }
    }
    else
    {
        OutputDebugStringA(szMsg);
    }

    if (!Dutil_fNoAsserts)
    {
        er = ::RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Delivery\\Debug", 0, KEY_QUERY_VALUE, &hkDebug);
        if (ERROR_SUCCESS == er)
        {
            cch = countof(szPath);
            er = ::RegQueryValueExA(hkDebug, "DeliveryAssertsLog", NULL, NULL, reinterpret_cast<BYTE*>(szPath), &cch);
            szPath[countof(szPath) - 1] = '\0'; // ensure string is null terminated since registry won't guarantee that.
            if (ERROR_SUCCESS == er)
            {
                hAssertFile = ::CreateFileA(szPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
                if (INVALID_HANDLE_VALUE != hAssertFile)
                {
                    ::SetFilePointer(hAssertFile, 0, 0, FILE_END);
                    ::StringCchCatA(szMsg, countof(szMsg), "\r\n");
                    ::WriteFile(hAssertFile, szMsg, lstrlenA(szMsg), &cch, NULL);
                }
            }
        }

        // if anything went wrong while fooling around with the registry, just show the usual assert dialog box
        if (ERROR_SUCCESS != er)
        {
            hr = ::StringCchCatA(szMsg, countof(szMsg), "\nAbort=Debug, Retry=Skip, Ignore=Skip all");
            ExitOnFailure(hr, "failed to concat string while building assert message");

            id = ::MessageBoxA(0, szMsg, "Debug Assert Message",
                MB_SERVICE_NOTIFICATION | MB_TOPMOST | 
                MB_DEFBUTTON2 | MB_ABORTRETRYIGNORE);
        }
    }

    if (id == IDABORT)
    {
        if (Dutil_hAssertModule)
        {
            ::GetModuleFileNameA(Dutil_hAssertModule, szPath, countof(szPath));

            hr = ::StringCchPrintfA(szMsg, countof(szMsg), "Module is running from: %s\nIf you are not using pdb-stamping, place your PDB near the module and attach to process id: %d (0x%x)", szPath, ::GetCurrentProcessId(), ::GetCurrentProcessId());
            if (SUCCEEDED(hr))
            {
                ::MessageBoxA(0, szMsg, "Debug Assert Message", MB_SERVICE_NOTIFICATION | MB_TOPMOST | MB_OK);
            }
        }

        ::DebugBreak();
    }
    else if (id == IDIGNORE)
    {
        Dutil_fNoAsserts = TRUE;
    }

LExit:
    ReleaseFileHandle(hAssertFile);
    ReleaseRegKey(hkDebug);
    fInAssert = FALSE;
}