如何在 C++ Builder IDE 中从 windows 注册表中读取 REG_MULTI_SZ?

How to read REG_MULTI_SZ from windows Registry in C++ Builder IDE?

当我尝试读取 REG_MULTI_SZ.

类型的注册表值时出现 Access violation at address xxxxxx in module (myApp.exe) Read of address 00000000 错误

我想从 windows 注册表项中读取 REG_MULTI_SZ 数据类型,并将结果添加到我的 TListBox 组件中,这是我用来执行此操作的代码:

void TSQLInstanceMain::GetSQLInstances(TStrings *AStrings)
{

    HKEY hkey;
    DWORD vType;
    DWORD vLen;
    DWORD buffer;
    wchar_t *p;
    UnicodeString RegKeyName  = L"\SOFTWARE\Microsoft\Microsoft SQL Server\";
    UnicodeString RegKeyValue = "InstalledInstances";

    try {
        if ( RegOpenKeyExW(HKEY_LOCAL_MACHINE, RegKeyName.w_str(), 0, KEY_READ | KEY_WOW64_64KEY, &hkey) == ERROR_SUCCESS )
        {
            SetLastErrorEx(RegQueryValueExW(hkey, RegKeyValue.w_str(), NULL, &vType, NULL, &vLen), NULL);

            if ( GetLastError() == ERROR_SUCCESS && vType == REG_MULTI_SZ  )
            {
                buffer = (DWORD)GetMemory(vLen);
                RegQueryValueExW(hkey, RegKeyValue.w_str(), NULL, NULL, PByte(buffer), &vLen);
                p = (wchar_t*)buffer;
                AStrings->Clear();
                while ( &p != 0x0 )
                {

                 AStrings->Add(p);
                 p += lstrlen(p)+1;

                }

            }
        }
    }
    __finally
    {
        FreeMemory(&buffer);
    }

}

注意:我在这个 article 中找到了这段代码,并尽我所能将其翻译成 C++。

AV 错误消息告诉您正在读取 NULL 指针。

我在您的代码中看到的一个错误可能是 while ( &p != 0x0 )。您的循环正在检查 p 指针本身的内存地址,而不是它指向的数据。因此,当指针到达字符串数据的末尾时,您的循环将不会正确终止。

您的循环应该是 while ( *p != 0 )(在 Delphi 中,p^ 是指针解引用),

您还应该过度分配 buffer 以包含您自己的空终止符,因为 RegQueryValueExW() 不保证字符串数据以空终止。在注册表中存储字符串数据的应用程序 应该 在存储的数据中包含空终止符,但存在许多错误的应用程序实际上并没有这样做。 RegQueryValueExW() 只是 returns 与保存时完全相同的原始数据,因此您读取的数据可能未正确以 null 终止,因此请附加您自己的终止符,以防万一:

wchar_t *buffer; // <-- not DWORD!
...
buffer = (wchar_t*) GetMemory(vLen + sizeof(wchar_t));
...
p = buffer;
...
FreeMemory(buffer); // <-- no &!

或者,使用 RegGetValueW() 代替,因为如果缺少终止符,它将为您附加一个空终止符。

最后,您正在泄露 RegOpenKeyExW() returns 的 HKEY。使用完 HKEY.

后,您需要调用 RegCloseKey()

综上所述,试试这个:

#include <vector>

void TSQLInstanceMain::GetSQLInstances(TStrings *AStrings)
{
    HKEY hkey;
    DWORD vType;
    DWORD vLen = 0;
    std::vector<BYTE> buffer;
    wchar_t *p;

    const wchar_t *RegKeyName  = L"\SOFTWARE\Microsoft\Microsoft SQL Server\";
    const wchar_t *RegKeyValue = L"InstalledInstances";

    if ( RegOpenKeyExW(HKEY_LOCAL_MACHINE, RegKeyName, 0, KEY_READ | KEY_WOW64_64KEY, &hkey) == ERROR_SUCCESS )
    {
        try
        {
            if ( (RegQueryValueExW(hkey, RegKeyValue, NULL, &vType, NULL, &vLen) == ERROR_SUCCESS) && (vType == REG_MULTI_SZ) )
            {
                vLen += sizeof(wchar_t);
                buffer.resize(vLen);
                RegQueryValueExW(hkey, RegKeyValue, NULL, &vType, &buffer[0], &vLen);
                p = (wchar_t*) &buffer[0];

                AStrings->BeginUpdate();
                try
                {
                    AStrings->Clear();
                    while ( *p != 0 )
                    {
                        AStrings->Add(p);
                        p += (lstrlenW(p) + 1);
                    }
                }
                __finally
                {
                    AStrings->EndUpdate();
                }
            }
        }
        __finally
        {
            RegCloseKey(hKey);
        }
    }
}

或:

#include <vector>

void TSQLInstanceMain::GetSQLInstances(TStrings *AStrings)
{
    HKEY hkey;
    DWORD vLen = 0;
    std::vector<BYTE> buffer;
    wchar_t *p;

    const wchar_t *RegKeyName  = L"\SOFTWARE\Microsoft\Microsoft SQL Server\";
    const wchar_t *RegKeyValue = L"InstalledInstances";

    if ( RegOpenKeyExW(HKEY_LOCAL_MACHINE, RegKeyName, 0, KEY_READ | KEY_WOW64_64KEY, &hkey) == ERROR_SUCCESS )
    {
        try
        {
            if ( (RegGetValueW(hkey, NULL, RegKeyValue, RRF_RT_REG_MULTI_SZ, NULL, NULL, &vLen) == ERROR_SUCCESS) )
            {
                buffer.resize(vLen);
                RegGetValueW(hkey, NULL, RegKeyValue, RRF_RT_REG_MULTI_SZ, NULL, &buffer[0], &vLen);
                p = (wchar_t*) &buffer[0];

                AStrings->BeginUpdate();
                try
                {
                    AStrings->Clear();
                    while ( *p != 0 )
                    {
                        AStrings->Add(p);
                        p += (lstrlenW(p) + 1);
                    }
                }
                __finally
                {
                    AStrings->EndUpdate();
                }
            }
        }
        __finally
        {
            RegCloseKey(hKey);
        }
    }
}