2013-04-30 24 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; 
    }  
} 


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