|
Hello,
I'm using you little registry class library and I must say that it does the job almost perfect! I found a little "feature" which I don't know if it's there on purpose or as a surprise..
This "feature" is in the constructor / read method of the CRegBase derived classes. This is what happens:
I call the constructor with a default value. The registry value / key don't exist yet. The read function returns the default value. The variable m_value doesn't change! So after the constructor finished the object has an invalid default value. (Not the one I specified.)
The code now looks like this:
<br />
m_value = "";<br />
m_defaultvalue = def;<br />
m_force = force;<br />
m_base = base;<br />
m_read = FALSE;<br />
key.TrimLeft(_T("\\"));<br />
m_path = key.Left(key.ReverseFind(_T('\\')));<br />
m_path.TrimRight(_T("\\"));<br />
m_key = key.Right(key.GetLength() - key.ReverseFind(_T('\\')));<br />
m_key.Trim(_T("\\"));<br />
read();<br />
<br />
ASSERT(m_key != _T(""));<br />
if (RegOpenKeyEx(m_base, m_path, 0, KEY_EXECUTE, &m_hKey)==ERROR_SUCCESS)<br />
{ <br />
int size = 0;<br />
DWORD type;<br />
RegQueryValueEx(m_hKey, m_key, NULL, &type, NULL, (LPDWORD) &size);<br />
TCHAR* pStr = new TCHAR[size];<br />
if (RegQueryValueEx(m_hKey, m_key, NULL, &type, (BYTE*) pStr,(LPDWORD) &size)==ERROR_SUCCESS)<br />
{<br />
m_value = CString(pStr);<br />
delete [] pStr;<br />
ASSERT(type==REG_SZ);<br />
m_read = TRUE;<br />
RegCloseKey(m_hKey);<br />
return m_value;<br />
} <br />
else<br />
{<br />
delete [] pStr;<br />
RegCloseKey(m_hKey);<br />
return m_defaultvalue;<br />
}<br />
}<br />
<br />
return m_defaultvalue;<br />
And I think that the code should look like this:
<br />
m_value = "";<br />
m_defaultvalue = def;<br />
m_force = force;<br />
m_base = base;<br />
m_read = FALSE;<br />
key.TrimLeft(_T("\\"));<br />
m_path = key.Left(key.ReverseFind(_T('\\')));<br />
m_path.TrimRight(_T("\\"));<br />
m_key = key.Right(key.GetLength() - key.ReverseFind(_T('\\')));<br />
m_key.Trim(_T("\\"));<br />
<br />
read();<br />
<br />
ASSERT(m_key != _T(""));<br />
if (RegOpenKeyEx(m_base, m_path, 0, KEY_EXECUTE, &m_hKey)==ERROR_SUCCESS)<br />
{ <br />
int size = 0;<br />
DWORD type;<br />
RegQueryValueEx(m_hKey, m_key, NULL, &type, NULL, (LPDWORD) &size);<br />
TCHAR* pStr = new TCHAR[size];<br />
if (RegQueryValueEx(m_hKey, m_key, NULL, &type, (BYTE*) pStr,(LPDWORD) &size)==ERROR_SUCCESS)<br />
{<br />
m_value = CString(pStr);<br />
delete [] pStr;<br />
ASSERT(type==REG_SZ);<br />
m_read = TRUE;<br />
RegCloseKey(m_hKey);<br />
return m_value;<br />
} <br />
else<br />
{<br />
delete [] pStr;<br />
RegCloseKey(m_hKey);<br />
<br />
<br />
}<br />
}<br />
<br />
return (m_value = m_defaultvalue);<br />
I think that option 2 is the better option, because that way m_value is always changed, which I thinkt is the purpose of the read() method.
Besides that, it's a great class!
I also got the blogging virus..[^]
|
|
|
|
|
and sure Trim is not a member of CString, then...
|
|
|
|
|
I think that maybe it's a bug.
I think that it maybe should like this:
m_key.TrimLeft(_T("\\"));
And i believe it is right with trimleft().
|
|
|
|
|
Trim is now a member of the old MFC CString class, but here is what google found:
"The trimChars can be either a string of the characters or an integer array of characters that will be trimmed from both ends"
so instead of
string.Trim()
i used
string.TrimLeft();
string.TrimRight();
so far it works,
Sincerely,
Alex Chirokov
|
|
|
|
|
Yes, Trim is a valid CString function... BUT.. it returns the result rather than changing the object directly. So the line MyString.trim() , while being valid code, will have no effect as the result is lost... It needs to be written CString szTrimmed = MyString.Trim() , and now the result of the Trim() operation is captured in the szTrimmed variable.
Trim operates on both ends of the string as opposed to TrimLeft and TrimRight which operate on only one end -- so if MyString = "*****Important String!!!!!!" , you could use szTrimmed = MyString.Trim("*!"); and the result would be "Important String".
The important point here is that the reason there is data loss in the example code, is because he didn't assign a variable to catch the returned result of the Trim operation.
In business, if two people always agree, one of them is unnecessary.
|
|
|
|
|
The .reg file saved by RegSaveKey() is a binary file.
How to export registry as an ASCII text file?
|
|
|
|
|
Hello,
No problem when I use removeValue(),
however; when I use removeKey() I get linker errors?
How do I fix the linker errors, or how can
I remove keys without using removeKey()?
Linking...
maindoc.obj : error LNK2001: unresolved external symbol __imp__SHDeleteKeyA@8
../../Apps/Debug/SPMNotify.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.
VC++ 6.0 SP5
Thanks,
Jacques
|
|
|
|
|
Just add Shlwapi.lib import library to your VS 5 project (Project/Settings/Settings for all configurations/Link/Object/library modules).
|
|
|
|
|
thanks for posting this outstanding code!
|
|
|
|
|
Is there any way to use this registry class in program that does not support MFC?
I would like to use this registry class in an existing DLL that does not support MFC. I think it is rather difficult to make that DLL to support MFC, so I would like to see if there is any way to use this class with no support of MFC.
I am definitely open to the suggestion on how to change a DLL to support MFC with minimum effort.
Thanks,
LT
|
|
|
|
|
This is one heck of a class library!
keep up the great work!
|
|
|
|
|
Hi,
Do you know how to load an entire .reg file programmatically?
I didn't see that anywhere ?
Thanks.
|
|
|
|
|
Thought this little bit may be of use for some.
The class declares CRegStdWORD instead of CRegStdDWORD as you (and I) would expect. Those programs referencing CRegStdDWORD will not compile. Since I did not want to change a lot of the code, adding this line to the end of registry.h provides a quick fix:
typedef CRegStdWORD CRegStdDWORD;
Thanks for the great class!
|
|
|
|
|
This was exactly what I was looking for. thanks a lot for writing it.
|
|
|
|
|
Congratulations ; is just what I was looking for, thanks a lot.
People say that I am a perverse person, but are not truth because I have the heart of a boy.... I have it in a bottle with formol in my writing-desk.
|
|
|
|
|
Hi,
I am getting the following linker error:
error LNK2001: unresolved external symbol "public: class CRegStdWORD & __thiscall CRegStdWORD::operator=(unsigned long)" (??4CRegStdWORD@@QAEAAV0@K@Z)
Debug/StickyNotes.exe : fatal error LNK1120: 1 unresolved externals.
Looks like CRegStdWORD::operator=(DWORD d) is not defined.
Is it a bug or a feature? Or am I missing something?
With respect,
Igor.
|
|
|
|
|
Yes, I'm getting the same thing when trying to link to the CRegistry code, part of another DLL. Looks like it isn't exported for some reason. Help?
error LNK2001: unresolved external symbol "public: class CRegStdWORD & __thiscall CRegStdWORD::operator=(unsigned long)" (??4CRegStdWORD@@QAEAAV0@K@Z)
|
|
|
|
|
You need to define CRegStdWORD::operator=(DWORD d) yourself. Looks like it's just missing. After I implemented it I was able to compile the project.
Igor.
|
|
|
|
|
Hello,
The class generated 3 compiler errors. All 3 compiler
errors were generated from the 3 occurrences of the
statement:
//generates compiler error.
m_key.Trim(_T("\\"));
Compiler error message:
Registry.cpp(135) : error C2039: 'Trim' : is not a member of 'CString'
However, I replaced all 3 statements with:
// m_key.Trim(_T("\\"));
m_key = m_key.Mid(1);
and all is well.
Regards,
Jacques
|
|
|
|
|
Yes, Trim is a new function in VC7 / .NET.
I think I just replaced that one with TrimLeft + TrimRight.
|
|
|
|
|
your code helped me a lot. many thx 4 that.
to get the value of registry's "(Default)" entries i suggest to not making any assertions on the given key in the read() methods.
|
|
|
|
|
This is a great idea for a regitry class. Thx for that pice off code.
|
|
|
|
|
** Original post 8/2003. Modified 12/2004 **
I had a need to read & write to the registry, and I found this article to be the best assistance to me. I did however eventually need to use it with REG_MULTI_SZ so I could it's capabilities for a project I needed to do.
Anyhow, here's the code. Add this to the source in this article:
Registry.h
class CRegMultiString : public CRegBase
{
public:
CRegMultiString();
/**
* Constructor.
* \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
* \param def the default value used when the key does not exist or a read error occured
* \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
* \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
*/
CRegMultiString(CString key, CString def = _T(""), BOOL force = FALSE, HKEY base = HKEY_CURRENT_USER);
~CRegMultiString(void);
CString read(); ///< reads the value from the registry
void write(); ///< writes the value to the registry
operator CString();
CRegMultiString& operator=(CString s);
CRegMultiString& operator+=(CString s) { return *this = (CString)*this + s; }
protected:
CString m_value; ////< the cached value of the registry
CString m_defaultvalue; ///< the default value to use
BOOL m_read; ///< indicates if the value has already been read from the registry
BOOL m_force; ///< indicates if no cache should be used, i.e. always read and write directly from registry
};
Registry.cpp
CRegMultiString::CRegMultiString(void)
{
m_value = _T("");
m_defaultvalue = _T("");
m_key = _T("");
m_base = HKEY_CURRENT_USER;
m_read = FALSE;
m_force = FALSE;
}
/**
* Constructor.
* @param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
* @param def the default value used when the key does not exist or a read error occured
* @param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
* @param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
*/
CRegMultiString::CRegMultiString(CString key, CString def, BOOL force, HKEY base)
{
m_value = "";
m_defaultvalue = def;
m_force = force;
m_base = base;
m_read = FALSE;
key.TrimLeft(_T("\\"));
m_path = key.Left(key.ReverseFind(_T('\\')));
m_path.TrimRight(_T("\\"));
m_key = key.Right(key.GetLength() - key.ReverseFind(_T('\\')));
m_key.Trim(_T("\\"));
read();
}
CRegMultiString::~CRegMultiString(void)
{
//write();
}
// *** Modified 12/04 ***
CString CRegMultiString::read()
{
ASSERT(m_key != _T(""));
if (RegOpenKeyEx(m_base, m_path, 0, KEY_EXECUTE, &m_hKey)==ERROR_SUCCESS)
{
int size = 0;
DWORD type;
RegQueryValueEx(m_hKey, m_key, NULL, &type, NULL, (LPDWORD) &size);
TCHAR* pStr = new TCHAR[size];
if (RegQueryValueEx(m_hKey, m_key, NULL, &type, (BYTE*) pStr,(LPDWORD) &size)==ERROR_SUCCESS)
{
m_value = CString(pStr);
delete [] pStr;
ASSERT(type==REG_SZ);
m_read = TRUE;
RegCloseKey(m_hKey);
return m_value;
}
else
{
delete [] pStr;
RegCloseKey(m_hKey);
return m_defaultvalue;
}
}
return m_defaultvalue;
}
/// *** End modification
void CRegMultiString::write()
{
ASSERT(m_key != _T(""));
DWORD disp;
if (RegCreateKeyEx(m_base, m_path, 0, _T(""), REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &m_hKey, &disp)!=ERROR_SUCCESS)
{
return;
}
#ifdef _UNICODE
if (RegSetValueEx(m_hKey, m_key, 0, REG_MULTI_SZ, (BYTE *)(LPCTSTR)m_value, (m_value.GetLength()+1)*2)==ERROR_SUCCESS)
#else
if (RegSetValueEx(m_hKey, m_key, 0, REG_MULTI_SZ, (BYTE *)(LPCTSTR)m_value, m_value.GetLength()+1)==ERROR_SUCCESS)
#endif
{
m_read = TRUE;
}
RegCloseKey(m_hKey);
}
CRegMultiString::operator CString()
{
if ((m_read)&&(!m_force))
return m_value;
else
{
return read();
}
}
CRegMultiString& CRegMultiString::operator =(CString s)
{
if ((s==m_value)&&(!m_force))
{
//no write to the registry required, its the same value
return *this;
}
m_value = s;
write();
return *this;
}
|
|
|
|
|
I don't get it. Why are you calling RegQueryValueEx FOUR times for the same key in CRegMultiString::read() ??
The first one is to get the length of the value, which is used to allocate a buffer that you fill with the second call, but then there's a fixed 64000 byte buffer and two more calls, why?
Am I missing something?
|
|
|
|
|
Hi,
When I first modified the code to read multi-string I was just grabbing other pieces from this class and modifying it. I obviously didn't need all those calls to RegQueryValueEx. It does work however as I get the results I wanted. I wasn't really paying attention to the details when I posted the note and I'm a bit more experienced at coding now than I was back then. The following bit of code should get you the same results without all the extra coding. I honestly don't remember where I got the bit to read multistring reg values as I didn't come up with the code in it's entirety. I just applied it to this class because I found it useful and thought someone else may need to read/write multistring values like I did.
Here's the same code that's used by CRegString and also works for reading multistrings.
CString CRegMultiString::read()
{
ASSERT(m_key != _T(""));
if (RegOpenKeyEx(m_base, m_path, 0, KEY_EXECUTE, &m_hKey)==ERROR_SUCCESS)
{
int size = 0;
DWORD type;
RegQueryValueEx(m_hKey, m_key, NULL, &type, NULL, (LPDWORD) &size);
TCHAR* pStr = new TCHAR[size];
if (RegQueryValueEx(m_hKey, m_key, NULL, &type, (BYTE*) pStr,(LPDWORD) &size)==ERROR_SUCCESS)
{
m_value = CString(pStr);
delete [] pStr;
ASSERT(type==REG_SZ);
m_read = TRUE;
RegCloseKey(m_hKey);
return m_value;
}
else
{
delete [] pStr;
RegCloseKey(m_hKey);
return m_defaultvalue;
}
}
return m_defaultvalue;
}
|
|
|
|
|