Serializing CStringList in the registry

The registry is an ideal place to store information about your application. Using a key and a Value Name you can easily store and retrieve Value Data once you get a hang of the registry APIs.

I recently encountered a scenario where I needed to store a list of strings in the registry. Typically, that would involve ::RegOpenKeyEx(key) followed by a series of ::RegSetValueEx(ValueName, ValueData). Unfortunately, I didn't have any Value Names for the list of strings to store. In other words, if I have 5 strings to write into the registry, I would need to generate 5 different Value Names to uniquely identify each string. Here's what the registry would look like:

Key:
SOFTWARE\Commpany\App\strings

Value Name and Value Data:
a = "string1"
b = "string2"
c = "string3"
d = "string4"
e = "string5"

The downside of this technique is the excessive number of Value Names, and the pseudo-random generation of those names. My original need of storing N strings would be better served by specifying only one Value Name along with a string list.

The technique I implemented consists of serializing a CStringList using MFCs CMemFile, CArchive and the registry's REG_BINARY data type. The registry is not the appropriate place to store massive amounts of data, and anything over 2K should be stored as a separate file outside the registry. Therefore, I placed a hard coded limit of 4096 bytes for the string list.

The code was tested using Microsoft Visual C++ 5.0sp3 under Windows 95.

// skip registry key opening sequence for clarity
const INT nSIZE = 4096;
DWORD dwType;
DWORD dwData  = nSIZE;
BYTE* bData   = (BYTE*)::calloc(nSIZE, sizeof(TCHAR));
ASSERT(bData);

const LONG retValue = ::RegQueryValueEx(hKey, pszValueName, NULL, &dwType,
bData, &dwData);

if(retValue == ERROR_SUCCESS and REG_BINARY == dwType){
ASSERT(dwData < nSIZE);
try{
  // Read
  CMemFile file(bData, nSIZE);
  CArchive ar(&file, CArchive::load);
  ar.m_bForceFlat = FALSE;
  ASSERT( ar.IsLoading() );
  CStringList myList;
  ASSERT( myList.IsSerializable() );
  myList.Serialize(ar);
  ar.Close();
  file.Close();

  myList.AddTail("Another string!");

  // Write
  file.Attach(bData, nSIZE, 16);
  CArchive ar2(&file, CArchive::store);
  ASSERT(myList.IsSerializable());
  myList.Serialize(ar);
  ar2.Close();
  const DWORD dwLen = file.GetLength();
  ASSERT(dwLen < nSIZE);
  ::RegSetValueEx(hKey, pszValueName, 0, REG_BINARY, file.Detach(), dwLen);
}
catch(CMemoryException* e){
  e->ReportError();
  e->Delete();
}
catch(CArchiveException* e){
  e->ReportError();
  e->Delete();
}
catch(CFileException* e){
  e->ReportError();
  e->Delete();
}
if(bData) free(bData); bData = NULL;
}



Comments

  • Registry key

    Posted by Legacy on 05/14/2003 12:00am

    Originally posted by: Bhargavi

    It is nice we have tested code in C++. Can we apply same logic in Java??

    Reply
  • Ah it's not true you don't need more than one value :(

    Posted by Legacy on 03/10/2000 12:00am

    Originally posted by: Tobias Sch�nherr

    When you look at the docs you'll see that there's a value type REG_MULTI_SZ. It defines a registry key that stores strings separated with 00.
    
    

    Here's my small sample code

    void CRegistry::GetStringList(LPCTSTR SubKey, LPCTSTR Value, CStringList &SL)
    {
    HKEY hKey;
    if(RegOpenKeyEx(m_hKey, SubKey,0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
    {
    DWORD ValueType;
    if(RegQueryValueEx(hKey, Value, NULL, &ValueType, NULL, NULL) == ERROR_SUCCESS)
    {
    if(ValueType == REG_MULTI_SZ)
    {
    char ca[64000];
    DWORD BufLen = 64000;
    if(RegQueryValueEx(hKey, Value, NULL, NULL, NULL, &BufLen) == ERROR_SUCCESS)
    {
    if(BufLen > 1)
    {
    if(RegQueryValueEx(hKey, Value, NULL, NULL, (LPBYTE)ca, &BufLen) == ERROR_SUCCESS)
    {
    unsigned int begin = 0;
    for(unsigned int ipos=0; ipos<64000; ipos++)
    {
    if(ca[ipos] == '\0')
    {
    CString s;
    for(unsigned int ipos2=begin; ipos2 < ipos; ipos2++)
    {
    s += ca[ipos2];
    }
    SL.AddTail(s);
    begin = ipos+1;
    if(ca[begin] == '\0') break;
    }
    }
    }
    }
    }
    }
    }
    RegCloseKey(hKey);
    }
    }

    void CRegistry::PutStringList(LPCTSTR SubKey, LPCTSTR Value, CStringList &SL)
    {
    HKEY hKey;

    if(RegCreateKeyEx(m_hKey, SubKey, 0, _T(""),
    REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS)
    {
    CString String;

    for(POSITION pos = SL.GetHeadPosition(); pos != NULL; )
    {
    String += SL.GetAt(pos);
    String += '\0';

    SL.GetNext(pos);
    }
    String += '\0';

    RegSetValueEx(hKey, Value, 0, REG_MULTI_SZ, (LPBYTE)(LPCTSTR)String, String.GetLength());
    RegCloseKey(hKey);
    }
    }

    By Tobias ;)

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date