2013-04-30 55 views
3

我想制作一个程序,它从Windows注册表中收集一些信息,然后将其保存到文件中。但是,我收集信息遇到问题。我想在一个结构中存储一个数组。我的问题是在初始化结构之后指定数组的大小。内存分配(键值)对结构,并从注册表中读取

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; 
} 
+7

,如果你用C++写的,使用'的std :: vector's和'的std :: string's会更容易些。 – juanchopanza 2013-04-30 13:52:19

+3

很难确定(特别是因为您没有发布'ReadRegistry'的代码),但我会说您不知道如何在C++中进行动态内存分配,甚至不知道指针如何工作。可能你只需要花一些时间阅读一本C++书籍。有很多方法可以解决这个问题,但最重要的是让你更好地理解问题。 – john 2013-04-30 13:56:50

+2

最有可能的是,您的ReadRegistry函数正在从注册表中读取一个静态缓冲区,并返回指向该静态缓冲区的指针。你正在保存的是哪个。但是你每次都得到相同的指针。 – TazMainiac 2013-04-30 13:58:35

回答

1

ResultsValues变量是一个指针,所以你需要为它分配内存之前,您可将“ReadRegistry”到它的结果。

如果'ReadRegistry'是你写的函数,返回值的类型是什么?如果它是一个指针,那么在函数中也可能存在内存分配问题,您可能需要使用CString作为返回值或将结果指针作为参数。

注意:之后您还需要释放分配的内存!

编辑

一)使函数void ReadRegistry(LPTSTR clave, LPTSTR valor, LPTSTR infocadena)

b)删除的变量infocadenabuffer声明,并在功能

的C buffer所有引用:已编辑的问题发表评论)在调用逻辑中为RES_OS_Keys[l].ResultsValues分配内存,然后调用函数,如ReadRegistry((LPTSTR) clave,(LPTSTR)RES_OS_Keys[l].ResultsKeys, RES_OS_Keys[l].ResultsValues);

d)释放分配的内存之后

3

请你帮个忙和:

  1. 删除原始字符串指针的这种过时的错误倾向难以写型和维护的C风格,原始数组等等和使用C++(可能有一些方便的C++ 11功能)和STL容器和类(如std::mapstd::wstring,...)。

  2. 丢弃陈旧的TCHAR模型,并且只写Unicode Win32代码。

下面的代码使用C++,STL和RAII和接口的Win32 API。
错误使用C++异常来表示。
字符串存储在健壮的std::wstring类实例中。
(键值)对存储在方便的STL容器中。

该代码已注释,因此请按照代码内的注释了解更多详细信息。

为了测试,我创建上的注册表一些测试数据(如在下面的截图显示): Some registry test data

,然后用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; 
    }  
} 


/////////////////////////////////////////////////////////////////////////////