我想创建一个程序,它从Windows注册表中收集一些信息,然后将其保存到文件中。但是我收集信息时遇到了问题。我想在一个结构中存储一个数组。我的问题是在初始化struct之后指定数组的大小。
typedef struct RESULTSKEY{
char *ResultsKeys;
char *ResultsValues;
} RESULTSKEYS;
RESULTSKEYS RES_OS_Keys[] =
{
{ _T("ProductName"),_T(" ")},
{ _T("CSDVersion"),_T(" ") },
{ _T("BuildLab"),_T(" ") },
{ _T("SystemRoot"),_T(" ") },
};
然后使用以下功能,应该发生魔法。
for (l=0; l< _countof(RES_OS_Keys);l++)
{
variable = (char*)ReadRegistry((LPTSTR) clave,(LPTSTR)RES_OS_Keys[l].ResultsKeys);
RES_OS_Keys[l].ResultsValues = variable;
}
但当然有一个问题:RES_OS_Keys[l].ResultsValues
具有相同的值:
RES_OS_Keys[0]
{ ResultsKeys=0x00420894"ProductName" Resultsvalues=0x0012f488 "C:\WINDOWS"}
RES_OS_Keys[1]
{ ResultsKeys=0x00420880"CSDVersion" Resultsvalues=0x0012f488 "C:\WINDOWS"}
RES_OS_Keys[2]
{ ResultsKeys=0x00420874"ProductName" Resultsvalues=0x0012f488 "C:\WINDOWS"}
RES_OS_Keys[3]
{ ResultsKeys=0x00420864"ProductName" Resultsvalues=0x0012f488 "C:\WINDOWS"}
我注意到它写在同一个内存段上。这就是为什么我提出这个想法,问题是结构中变量的内存分配。我一直在寻找方法,但是我很困惑。所以,如果有人可以给我一个建议,我将不胜感激。
以下是ReadRegistry
功能:
unsigned char *ReadRegistry(LPTSTR clave, LPTSTR valor)
{
unsigned char* buffer =new unsigned char[1024];
unsigned char infoValue [1024];
unsigned char infocadena [1024];
HKEY hKey;
LONG lStatus;
DWORD dwType=REG_SZ;
DWORD dwSize=1023;
int i=0;
int j=0;
lStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,clave,0,KEY_READ|KEY_WOW64_64KEY,&hKey);
if (lStatus == ERROR_SUCCESS)
{
lStatus = RegQueryValueEx(hKey,(LPCTSTR )valor, 0,&dwType, (LPBYTE)&infoValue, &dwSize);
if (lStatus == ERROR_SUCCESS)
{
for(i=0;infoValue[i]!=0 && infoValue[i]!=204;i++)
infocadena[i]=(char)infoValue[i];
infocadena [i]='\0';
buffer = infocadena;
RegCloseKey(hKey);
return buffer;
delete[] buffer;
}
}
RegCloseKey(hKey);
cout << "error by reading registry";
delete[] buffer;
return 0;
}
答案 0 :(得分:3)
帮自己一个忙,并且:
删除这个过时的容易出错的难以写入的读取和维护C样式的原始字符串指针,原始数组等,以及使用C ++ (可能还有一些方便的C ++ 11功能)和 STL 容器和类(如std::map
,std::wstring
,...)。
删除过时的TCHAR
模型,然后编写 Unicode Win32代码。
以下代码使用C ++,STL和RAII以及与Win32 API的接口
使用C ++异常表示错误
字符串存储在健壮的std::wstring
类实例中
(键,值)对存储在方便的std::map
STL容器中。
代码已注释,因此请按照代码中的注释获取更多详细信息。
为了测试,我在注册表上创建了一些测试数据(如下面的屏幕截图所示):
然后使用VC10(VS2010 SP1)从命令行编译代码:
C:\Temp\CppTests>cl /EHsc /W4 /nologo /MTd TestRegistry.cpp TestRegistry.cpp
并运行可执行文件,获取以下输出:
C:\Temp\CppTests>TestRegistry.exe BuildLab: Cool LAB ProductName: My Cool Product. Version: 1.2.3.4A
可编辑的代码如下:
/////////////////////////////////////////////////////////////////////////////
//
// Test program to read some strings from the registry.
//
// Uses C++ techniques like RAII and STL containers.
//
/////////////////////////////////////////////////////////////////////////////
// Build in Unicode mode
// (it's the default inside VS IDE, since VS2005).
#define UNICODE
#define _UNICODE
//
// Headers:
//
#include <exception> // for std::exception
#include <iostream> // for console output
#include <map> // for std::map
#include <stdexcept> // for std::runtime_error
#include <string> // for std::wstring
#include <Windows.h> // Win32 Platform SDK
// Link with this for registry APIs.
#pragma comment(lib, "advapi32.lib")
//
// Represents Win32 API errors.
//
class Win32Error
: public std::runtime_error
{
public:
// Init with message and error code
Win32Error(const char* message, DWORD error)
: std::runtime_error(message),
m_error(error)
{
}
DWORD ErrorCode() const
{
return m_error;
}
private:
DWORD m_error;
};
// Throws Win32Error exception based on last error code.
inline void ThrowLastWin32(const char* message)
{
const DWORD lastError = ::GetLastError();
throw Win32Error(message, lastError);
}
//
// RAII wrapper to Win32 registry key.
//
class RegKey
{
public:
// Tries opening the specified key.
// Throws a Win32Error exception on failure.
RegKey(
HKEY hKeyParent,
const std::wstring& subKey,
REGSAM desideredAccess
)
{
LONG result = ::RegOpenKeyEx(
hKeyParent,
subKey.c_str(),
0,
desideredAccess,
&m_hKey
);
if (result != ERROR_SUCCESS)
{
ThrowLastWin32("Can't open registry key.");
}
}
// Closes the key.
~RegKey()
{
::RegCloseKey(m_hKey);
}
// Gets the wrapped key handle.
HKEY Get() const
{
return m_hKey;
}
private:
HKEY m_hKey; // raw key resource wrapper in this RAII class
};
//
// Reads a string from the registry.
// (Throws exceptions like Win32Error on errors.)
//
std::wstring ReadRegistryString(
HKEY hKeyParent,
const std::wstring& keyName,
const std::wstring& value)
{
// Try opening the specified key
RegKey key( hKeyParent, keyName, KEY_READ|KEY_WOW64_64KEY);
// First call to ::RegQueryValueEx() to get destination buffer size
DWORD dataSize = 0;
LONG result = ::RegQueryValueEx(
key.Get(), // handle to open registry key
value.c_str(), // the name of the registry value
nullptr, // reserved
nullptr, // no need to know the type of value
nullptr, // data is not required in this step
&dataSize // get data size, in bytes
);
if (result != ERROR_SUCCESS)
ThrowLastWin32("ReadRegistryString - Can't get buffer size.");
// Create a string with proper size to store the value
// read from registry.
// Consider that sizeof(wchar_t) == 2 bytes.
std::wstring data( dataSize/2, 'x' );
// Second call to ::RegQueryValueEx() to get the actual string
DWORD type;
result = ::RegQueryValueEx(
key.Get(), // handle to open registry key
value.c_str(), // the name of the registry value
nullptr, // reserved
&type, // the type of value
reinterpret_cast<BYTE*>(&data[0]), // string buffer
&dataSize // data size, in bytes
);
if (result != ERROR_SUCCESS)
ThrowLastWin32("ReadRegistryString - Can't get value data.");
// Check that we are reading a string
if (type != REG_SZ)
throw Win32Error("ReadRegistryString - Type is not string.",
ERROR_INVALID_DATA);
// To avoid duouble-NUL termination,
// remove the last NUL in the string, if present.
// (In fact, there can be a NUL copied by ::RegQueryValueEx,
// and there is the NUL of std::wstring).
if (data[data.length()-1] == L'\0')
data.resize(data.length()-1);
return data;
}
//
// Test function: read some key/value pairs from the registry.
//
std::map<std::wstring, std::wstring> ReadDesideredKeyValuePairs()
{
// Keys to read value for
const wchar_t* keys[] = {
L"ProductName",
L"Version",
L"BuildLab"
};
// Will store (key, value) pairs
std::map<std::wstring, std::wstring> result;
// Read key/value pairs from the registry
for (int i = 0; i < _countof(keys); i++)
{
result[keys[i]] = ReadRegistryString(
HKEY_CURRENT_USER,
L"C64Test",
keys[i]
);
}
return result;
}
//
// Console app entry point
//
int main()
{
static const int kExitOk = 0;
static const int kExitError = 1;
try
{
// Call test function
std::map<std::wstring, std::wstring> result =
ReadDesideredKeyValuePairs();
// Print result to console
for (auto it = result.begin(); it != result.end(); ++it)
std::wcout << it->first << ": " << it->second << std::endl;
// All right
return kExitOk;
}
catch(const std::exception& e)
{
// Print error message
std::wcerr << "\n*** ERROR: " << e.what() << std::endl;
// Exit with failure code
return kExitError;
}
}
/////////////////////////////////////////////////////////////////////////////
答案 1 :(得分:1)
ResultsValues
变量是一个指针,因此您需要先为其分配内存,然后才能将“ReadRegistry”的结果存储到其中。
如果'ReadRegistry'是您编写的函数,返回值的类型是什么?如果它是一个指针,你也可能在函数中有内存分配问题,你可能想要使用CString作为返回值或者将结果指针作为参数。
注意:之后你还需要释放分配的内存!
编辑:对已修改的问题发表评论:
a)制作函数void ReadRegistry(LPTSTR clave, LPTSTR valor, LPTSTR infocadena)
b)删除变量infocadena
和buffer
的声明以及函数中buffer
的所有引用
c)在调用逻辑中为RES_OS_Keys[l].ResultsValues
分配内存,然后像ReadRegistry((LPTSTR) clave,(LPTSTR)RES_OS_Keys[l].ResultsKeys, RES_OS_Keys[l].ResultsValues);
d)之后释放分配的内存