如何在 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);
}
}
}
当我尝试读取 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);
}
}
}