|
|
Comments and Discussions
|
|
 |

|
Is there any license limitation ?
|
|
|
|

|
Dear Robert, first thank's very much for share your code, nice Job,
I start to use it, and I need another functionaly, navigate trough subkeys, I add this fuctionaly to your class and I thing it's a good function to include in the article,
BOOL CRegistry::QuerySubKey(int index, CString& subkeyname)
{
TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name
DWORD cbName; // size of name string
TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name
DWORD cchClassName = MAX_PATH; // size of class string
DWORD cSubKeys=0; // number of subkeys
DWORD cbMaxSubKey; // longest subkey size
DWORD cchMaxClass; // longest class string
DWORD cValues; // number of values for key
DWORD cchMaxValue; // longest value name
DWORD cbMaxValueData; // longest value data
DWORD cbSecurityDescriptor; // size of security descriptor
FILETIME ftLastWriteTime; // last write time
DWORD i, retCode;
HKEY hKey;
ASSERT(m_strCurrentPath.GetLength() > 0);
if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0,
KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS) return FALSE;
TCHAR achValue[MAX_VALUE_NAME];
DWORD cchValue = MAX_VALUE_NAME;
// Get the class name and the value count.
retCode = RegQueryInfoKey(
hKey, // key handle
achClass, // buffer for class name
&cchClassName, // size of class string
NULL, // reserved
&cSubKeys, // number of subkeys
&cbMaxSubKey, // longest subkey size
&cchMaxClass, // longest class string
&cValues, // number of values for this key
&cchMaxValue, // longest value name
&cbMaxValueData, // longest value data
&cbSecurityDescriptor, // security descriptor
&ftLastWriteTime); // last write time
// Enumerate the subkeys, until RegEnumKeyEx fails.
if (cSubKeys)
{
if ((index < 0) || (index >= cSubKeys))
return FALSE;
cbName = MAX_KEY_LENGTH;
retCode = RegEnumKeyEx(hKey, index,
achKey,
&cbName,
NULL,
NULL,
NULL,
&ftLastWriteTime);
if (retCode == ERROR_SUCCESS)
{
subkeyname = achKey;
}
else
return FALSE;
}
::RegCloseKey(hKey);
return TRUE;
}
And a little example of how to use it:
m_reg.SetRootKey(HKEY_LOCAL_MACHINE);
if (m_reg.SetKey("Software\\NFFormDestiller\\ExportDrivers", FALSE)) {
for (int x = 0; x < m_reg.GetSubKeyCount(); x++) {
CString subkey;
if (m_reg.QuerySubKey(x, subkey)) {
CRegistry reg;
reg.SetRootKey(HKEY_LOCAL_MACHINE);
if (reg.SetKey("Software\\NFFormDestiller\\ExportDrivers\\"+subkey, FALSE)) {
CString desc = reg.ReadString("","");
int index = m_lstcfg.InsertItem(x,desc,0);
m_lstcfg.SetItemText(index,1,subkey);
}
}
}
}
Best Regards
Rey
|
|
|
|

|
I tried to write Systems IP address into registry. When UNICODE is not defined then i could see the value from registry. And if Unicode is defined then i'm seeing 4 square boxed in the place of IP address..
How to show the IP address in the registry though UNICODE is defined?
Code snippet:
int main(void)
{
HKEY hKey;
char name[] = "199.68.56.33";
RegOpenKeyExW(HKEY_LOCAL_MACHINE,L"SOFTWARE\\MyCompany\\\\InstallInfo", 0, KEY_ALL_ACCESS, &hKey);
RegSetValueEx(hKey, L"FTEBaseIPAddress", 0, REG_SZ, name, ((strlen(name)+1)*sizeof(TCHAR)) );
return 1;
}
ssssssssssssssssssssssss
ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
|
|
|
|

|
when enumerating the registry or passing across buffers is there a need to null terminate the buffer as shown below:
DWORD dwSize = MAX_PATH;
TCHAR szSubkeyName[MAX_PATH+1];
memset(szSubkeyName,0x00,sizeof(TCHAR)*(MAX_PATH+1));
while( RegEnumKeyEx(hKey,
dwIndex,
szSubkeyName,
&dwSize,
NULL,
NULL,
NULL,
&ftLastWriteTime) == ERROR_SUCCESS)
{
|
|
|
|

|
Hi Robert,
I hope you don't mind (and you are mentioned in it), but I took your excellent format of this class (CRegistry) and created a class that uses the nt.dll Native functions (e.g. NtCreateKey, NtDeleteKey, etc...). I did this because I have enjoyed you class for a long time and always use in apps that I write. I especially like the simplicity of it and that is why I adopted it for this new class I wrote "CNtRegistry" - link is below. Please take a look and let me know what you think?
There is a lot of added stuff in it like "Hiding Keys, Copying Keys/Values, Searching, Deleting recursively, etc...". I did this because I saw a lot of folks here asking for it.
http://www.codeproject.com/system/NtRegistry.asp[^]
Again, let me know what you think.
Regards,
Dan
|
|
|
|

|
I am trying to read a key of the type Binary, I do not see any function for this, The data is actually a person's name so I need to read a type Binary into a CSrting
Example: 44 00 6F 00 6E 00 20 00 4C 00 61 00 76 00 65 00 72 00 64 00 75 00 72 00 65
Converted=Don Laverdure
Any suggestions?
Cheers,
Don
|
|
|
|

|
Thanks for a useful class. It would be nice if WriteDword() specified REG_DWORD instead of REG_BINARY.
Jason
The question of whether computers can think is like the question of whether submarines can swim (Dijkstra)
|
|
|
|

|
Please note that there is a UNICODE bug in CRegistry::WriteString
the last parameter for RegSetValueEx should be number of bytes, NOT the existing number of characters, so it must be multiplied by sizeof(TCHAR) to fix it. It must also be cast to a DWORD to get rid of level 4 warnings.
Warren
|
|
|
|

|
I've noted that if you are a non-priviliged user and you want to read the Registry, you may encounter problem when you use CRegistry::KeyExists and CRegistry::SetKey.
This seems due to the fact that these methods call ::RegOpenKeyEx with KEY_ALL_ACCESS parameter. I've seen that if you use KEY_READ everything is ok.
I'm not familiar with Microsoft security access masks, MSDN says that KEY_ALL_ACCESS is a combination of KEY_READ, KEY_WRITE and KEY_CREATE_LINK but it is not clear whether the combination is AND or OR.
From this, it seems to me that KEY_ALL_ACCESS requires both read and write rights, the latter not being available to a non-priviliged user.
So, why KEY_ALL_ACCESS has been used for reading ? Isn't KEY_READ more appropriate ?
|
|
|
|

|
Thanks alot, thats exactly what I was looking for;)
|
|
|
|

|
Mr Robert, you made me ROBOT!!! No more words to utter!!!
cheers
Balkrishna Talele
|
|
|
|

|
This is an excellent piece of code Robert. It turned what was becoming a nightmarish task into a breeze! Thanks so much for sharing it!!
Karen
|
|
|
|

|
The original version limited textstrings to 255 characters, I needed more. I changed WriteString() and ReadString() to get what I wanted. The following doesn't have any limit and works well in Unicode too. This includes the code from my previous bugfix message.
BOOL CRegistry::WriteString(CString strName, CString strValue)
{
ASSERT(m_strCurrentPath.GetLength() > 0);
BOOL bSuccess = TRUE;
HKEY hKey;
if (::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0,
KEY_WRITE, &hKey) != ERROR_SUCCESS) return FALSE;
if (::RegSetValueEx( hKey,
LPCTSTR(strName),
NULL,
REG_SZ,
(LPBYTE) ( (const TCHAR*) strValue),
(strValue.GetLength()+1)*sizeof(TCHAR)
)
!= ERROR_SUCCESS) bSuccess = FALSE;
if (!m_bLazyWrite) ::RegFlushKey(hKey);
::RegCloseKey(hKey);
return bSuccess;
}
CString CRegistry::ReadString(CString strName, CString strDefault)
{
DWORD dwType = REG_SZ;
DWORD dwSize = 0;
BOOL bSuccess = TRUE;
HKEY hKey;
ASSERT(m_strCurrentPath.GetLength() > 0);
dwType = GetDataType(strName);
if (dwType != REG_SZ && dwType != REG_EXPAND_SZ)
{
return strDefault;
}
m_nLastError = ::RegOpenKeyEx(m_hRootKey, LPCTSTR(m_strCurrentPath), 0,
KEY_READ, &hKey);
if (m_nLastError != ERROR_SUCCESS) return strDefault;
::RegQueryValueEx( hKey,
LPCTSTR(strName),
NULL,
&dwType,
NULL, &dwSize);
dwSize += sizeof(TCHAR);
TCHAR* sz = new TCHAR[ dwSize/sizeof(TCHAR) ];
m_nLastError = ::RegQueryValueEx( hKey,
LPCTSTR(strName),
NULL,
&dwType,
(LPBYTE)sz,
&dwSize);
CString retValue;
if(bSuccess)
retValue = sz;
delete [] sz;
if (m_nLastError != ERROR_SUCCESS) bSuccess = FALSE;
::RegCloseKey(hKey);
if (!bSuccess) return strDefault;
return retValue;
}
|
|
|
|

|
Is there anyway to enumerate Key and Value entries?
|
|
|
|

|
I get the warning
"LINK : warning LNK4089: all references to "GDI32.dll" discarded by
/OPT:REF"
when building in Release Mode.
For testing I created a new dialogbased project and built it in Release Mode without any errors/warnings. After adding CRegistry class and rebuilding in Release Mode I got this warning. I only use the methods "SetRootKey", "SetKey", "WriteString", "ReadString", "ClearKey"
It builds without warnings in Debug Mode.
I'm using VC++6 (german version, latest SP) on Win2k.
--
Karl
|
|
|
|

|
I think this is an excellent class, but still it has a little problem .
If you working with Unicode and trying to write a string to the registry only the first half of the string is written. The reason: the length is calculated correctly but every character is 2 bytes. RegSetValueEx want's the size in bytes so it's necessary to multiply with 2. OK, no more details . Here is the fix:
Remove these lines:
#ifdef _UNICODE
if (::RegSetValueEx(hKey, LPCTSTR(strName), 0,
REG_SZ, (LPBYTE)sz, wcslen(sz) + 1)
!= ERROR_SUCCESS) bSuccess = FALSE;
#else
if (::RegSetValueEx(hKey, LPCTSTR(strName), 0,
REG_SZ, (LPBYTE)sz, strlen(sz) + 1)
!= ERROR_SUCCESS) bSuccess = FALSE;
#endif
…and replace width these:
if (::RegSetValueEx(hKey, LPCTSTR(strName), NULL,
REG_SZ, (LPBYTE)sz, (lstrlen(sz)+1)*sizeof(TCHAR))
!= ERROR_SUCCESS) bSuccess = FALSE;
Yes, these lines are enough to do the work in Unicode and none-Unicode versions.
|
|
|
|

|
I am trying to use the simple class but I am problably stupid
because I can t found how to get the default data of a Key.
I mean the value to entrer in the function ReadString("???", "***");
My registry :
(par défaut) REG_SZ Winzip <- Who to get this value
Content Type REG_SZ application/mac-binhex40
Any idees ?
|
|
|
|

|
I'm not even sure that this is the problem, but when I run my application using your CRegistry class, it seems to have a problem writing the keys when I run as a user that does not have administrative privileges. Do you know why this might be?
Here's my code:
void CPreferences::InitializeRegistry()
{
CRegistry Reg;
Reg.SetRootKey(HKEY_LOCAL_MACHINE);
if( !Reg.KeyExists( "Software\\Compact Power" ) )
{
Reg.CreateKey( "Software\\Compact Power" );
}
if( !Reg.KeyExists( "Software\\Compact Power\\BMS Monitor" ) )
{
Reg.CreateKey( "Software\\Compact Power\\BMS Monitor" );
}
if( !Reg.KeyExists( "Software\\Compact Power\\BMS Monitor\\Settings" ) )
{
Reg.CreateKey( "Software\\Compact Power\\BMS Monitor\\Settings" );
}
Reg.SetKey( "Software\\Compact Power\\BMS Monitor\\Settings", FALSE );
if( !Reg.ValueExists( "COMPORT" ) )
Reg.WriteString( "COMPORT", "COM1" );
if( !Reg.ValueExists( "PARITY" ) )
Reg.WriteString( "PARITY", "NONE" );
if( !Reg.ValueExists( "DATABITS" ) )
Reg.WriteString( "DATABITS", "8" );
if( !Reg.ValueExists( "STOPBITS" ) )
Reg.WriteString( "STOPBITS", "1" );
if( !Reg.ValueExists( "BAUDRATE" ) )
Reg.WriteString( "BAUDRATE", "57600" );
if( !Reg.ValueExists( "HANDSHAKING" ) )
Reg.WriteString( "HANDSHAKING", "NONE" );
if( !Reg.ValueExists( "RUNMODE" ) )
Reg.WriteString( "RUNMODE", "1" );
if( !Reg.ValueExists( "LASTDB" ) )
Reg.WriteString( "LASTDB", "" );
if( !Reg.ValueExists( "BASEDBDIR" ) )
Reg.WriteString( "BASEDBDIR", "C:\\BMSMonitorData" );
if( !Reg.ValueExists( "AUTOSAVE" ) )
Reg.WriteString( "AUTOSAVE", "5" );
if( !Reg.ValueExists( "SAVEDATA" ) )
Reg.WriteString( "SAVEDATA", "0" );
if( !Reg.ValueExists( "LOGFILE" ) )
Reg.WriteString( "LOGFILE", "" );
}
Thanks for your help.
-Matt
------------------------------------------
The 3 great virtues of a programmer:
Laziness, Impatience, and Hubris.
--Larry Wall
|
|
|
|

|
This is probably a dumb question, but Should this work with windows 98?
Thanks.
-Matt
------------------------------------------
The 3 great virtues of a programmer:
Laziness, Impatience, and Hubris.
--Larry Wall
|
|
|
|

|
Very nice job! This is very simple and intuitive! Nice work!
-Matt
------------------------------------------
The 3 great virtues of a programmer:
Laziness, Impatience, and Hubris.
--Larry Wall
|
|
|
|

|
I belive you could use a GenericRead()/GenericWrite() functions instead of all the ReadRect/WriteTime ect.
In all the above cases, you use the binary method for reading/writing, so I guess the only reason to give the users a whole set of function is to make their life easier... but, if the users know what they should read or write, why won't they use a simple type-cast instead?
give them a couple of functions like the following ones:
bool ReadGeneric(CString strKey, CString strValue, LPVOID lpData, DWORD& dwDataSize);
bool WriteGeneric(CString strKey, CString strValue, LPVOID lpData, DWORD dwDataSize);
and in there do a binary read/write with the given data and size.
the user will do the casting back and forth between these functions and the calling function.
simple, clean and useful.
and btw, nice work with the helper class thanks!
alpha+
|
|
|
|

|
I'd like to suggest adding the following function to your class. This allows querying of a remote registry.
BOOL RemoteConnection(CString strComputerName);
BOOL CRegistry::RemoteConnection(CString strComputerName)
{
if (RegConnectRegistry(strComputerName, m_hRootKey, &m_hRootKey)==ERROR_SUCCESS)
return TRUE;
else
return FALSE;
}
Please note : you must call SetRootKey before using RegConnectRegistry
i386 the source for Windows XP/2000/NT
http://www.i386.com
|
|
|
|

|
... does somebody know how to access the registry programmatically by a non administrative user? thanks, tobi
|
|
|
|

|
WriteDword function is creating a Binary value instead of a DWORD. To create a DWORD value, the functionshould use if (::RegSetValueEx(hKey, LPCTSTR(strName), 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue)) != ERROR_SUCCESS) bSuccess = FALSE; in the place of if (::RegSetValueEx(hKey, LPCTSTR(strName), 0, REG_BINARY, (LPBYTE)&dwValue, sizeof(dwValue)) != ERROR_SUCCESS) bSuccess = FALSE; Regards! asX
|
|
|
|

|
Robert,
Thanks for making such a kick ass class and releasing it.
You inspired me to release some wrapper classes that are useful as well.
This was well written and again, thanks
-- Dan
www.dancclark.com
|
|
|
|
|

|
This certainly made my life a little easier!
Thanks.
-Sean
----
"Vigilance With Pride"
|
|
|
|

|
This is a great little class. This is what OOP is all about.
A pity that more programmers don't stick to the adage "keep it simple".
I wonder why, I wonder why, I wonder why I wonderI wonder why, I wonder why, I wonder why I wonder ...
|
|
|
|

|
When you create a numeric value (Bool, int, dword) they are created as
REG_BINARY values. This created problems for me when i modified some registry
values for some third-party applications.
I simply changed the methods WriteBool, WriteInt and WriteDWord to use
REG_DWORD.
BTW, this class is really a time saver when accessing the registry.
Good work.
|
|
|
|

|
Nice simple class, thanks
I think that the input CString parameters should be changed to either CString const& or (preferrably) to LPCTSTR.
I've a copy with this latter change and also a couple of changes to allow it to work with WTL. Let me know if you'd like a copy.
There also appears to be no mention of license; can I assume it's public domain (free for all use)?
Thanks
PeteB
`I wouldn't say "he's not the smartest knife", I'd say "he's a spoon"`
|
|
|
|

|
How to change Ip address in windows 2000 registry? I found several branches containing Ip address, how to find the real IP address binding my NIC(TCP/IP)?
|
|
|
|

|
To the same Registry.cpp i add one fuction main()i.e
main()
{
CString m_strUserName;
CRegistry Reg;
Reg.SetRootKey(HKEY_CURRENT_USER);
if (Reg.SetKey("Software\\Misrosoft\\InternetAccountManager\\Accounts\\00000001", FALSE))
{
m_strUserName = Reg.ReadString("Account", "Account Name");
cout << "Account Name" << m_strUserName ;
return 0;
}
else
{
TRACE("Failed to open key\n");
}
}
it is clean compiling but while i am trying to execute Registry.exe it is the follwing error
Registry.obj : error LNK2001: unresolved external symbol "public: __thiscall CString::~CString(void)" (??1CString@@QAE@XZ)
please help me in solving this thing
advance thanks
Sridha
|
|
|
|

|
I find the class to be quite nice to us. It writes as expected to a Windows 98 registry.
I find however that it is not writing successfully to a Windows 95 registry. Has
anyone else experienced this, and if so, has anyone creatd a version of the class
that will write successfully to both a Windows 95 and Windows 98 registry?
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
|
A simple registry class
| Type | Article |
| Licence | |
| First Posted | 17 Nov 1999 |
| Views | 179,259 |
| Bookmarked | 65 times |
|
|