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: SOFTWARECommpanyAppstrings 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; }