Creating registry keys

Jan 2, 2012 at 11:27am
I'm having some problems creating/reading keys in the registry. I've checked MSDN but I think I just have a fundamental mis-understanding of how it works.

The key "MyKey" should be of type REG_DWORD and located in HKEY_LOCAL_MACHINE, \\SOFTWARE\\MyCompany

I am writing a function that will check if MyKey exists. If so, it will return the value, if not it will create the missing key and return a default value (that will overwrite the current value later on).

My code so far:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
int check_or_create(const char strKeyName[]) //strKeyName is "SOFTWARE\\MyCompany\\MyKey"
{	
	HKEY hKey = NULL;
	DWORD rtime;

	//Step 1: Open the key
	long sts = RegOpenKeyEx(HKEY_LOCAL_MACHINE, strKeyName, 0, KEY_READ, &hKey);

	//Step 2: If failed, create the key
	if (ERROR_NO_MATCH == sts || ERROR_FILE_NOT_FOUND == sts)
	{
		cout << "Creating registry key " << strKeyName << endl;

		long j = RegCreateKeyEx(HKEY_LOCAL_MACHINE, strKeyName, 0L, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL );
		
		if (ERROR_SUCCESS != j)
			cout << "Error: Could not create registry key " << strKeyName << endl << "\tERROR: " << j << endl;
		else
			cout << "Success: Key created" << endl;

		rtime = 0;
	}
	else if (ERROR_SUCCESS != sts)
	{
		cout << "Cannot open registry key " << strKeyName << endl << "\tERROR: " << sts << endl;
		rtime = 0;
	}
	else //If it already existed, get the value from the key.
	{
		DWORD length = sizeof(rtime);
		DWORD type = REG_DWORD;
		RegQueryValueEx(HKEY_LOCAL_MACHINE, strKeyName, 0 , (LPDWORD)&type, (LPBYTE)&rtime, &length);
	}

	RegCloseKey(hKey);

	//Return the current value of the key (0 if just created)
	return rtime;
}


Questions:
1. When the key is created, it just creates a new folder with a "Default" key. How can I create specific keys in the folder? There does not seem to be room for this in the RegCreateKeyEx() function.
2. How do I specify the type of the key? It defaults to REG_SZ but I want it to be REG_DWORD. I've tried just writing data into it, but that doesn't do anything (despite returning ERROR_SUCCESS).
Jan 2, 2012 at 12:40pm
closed account (DSLq5Di1)
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724923
Jan 2, 2012 at 1:41pm
Thanks, but I've already spent hours staring at that page.

If I use this as shown above, I end up with a folder "SOFTWARE\\MyCompany\\MyKey" with a (Default) key with a REG_SZ type.

I want a folder "SOFTWARE\\MyCompany" and MyKey as a key with a REG_DWORD type.
Jan 2, 2012 at 1:58pm
Sloppy's answer is good. You are just not seeing it, which is strange because your 3rd paragraph of your latest answer does what you need to do in your code: Separate the key name from the key value name. Then you can do the call to RegSetValueEx() using the HKEY from RegOpenKeyEx().

If you were to google for examples on RegSetValueEx(), chances are you'll see a wrapping function with a signature similar to this:

1
2
template<class T>
bool QueryRegValue(HKEY hive, LPCTSTR szKeyName, LPCTSTR szValue, T &value);


That should hint to the fact that you most easily operate when you have those separated.
Last edited on Jan 2, 2012 at 2:01pm
Jan 2, 2012 at 2:12pm
But if I use:
RegCreateKeyEx(HKEY_LOCAL_MACHINE, strKeyName,...)
It creates the folder "HKEY_LOCAL_MACHINE\\SOFTWARE\\MyCompany\\MyKey"

Does this mean that if should use RegCreateKeyEx(..., &hKey) to create:
"HKEY_LOCAL_MACHINE\\SOFTARE\\MyCompany"
And then use RegValueSetEx(hKey, "MyKey", ...) to create the key?
Jan 2, 2012 at 2:17pm
Yes, now you're starting to see the good picture. Google up some examples to make it 100% clear.
Jan 2, 2012 at 6:09pm
Thanks for the clarification webJose. Things are finally working!

I didn't understand that the key was the path and the value was the stored data.

One more question:
I'll be writing to update these values every 5 minutes. The main loop that calls this function runs at 500Hz (2ms). For performance reasons which option do you think I should take:

A) RegOpenKeyEx() and RegCloseKey() take a huge amount of time, leave the key open until the program ends.
B) RegOpenKeyEx() and RegCloseKey() take significant time, run them + get or set in a seperate thread
C) RegOpenKeyEx() and RegCloseKey() don't take much time, open and close them without a thread every 5 min as required.
Jan 2, 2012 at 6:42pm
Okay, I had troubles finding examples that had EVERYTHING and I am pretty proud of my accomplishment today so here is the code in case anyone else searches for this:

The code:
1. Opens a key and creates it if it doesn't exist.
2. Reads values (DWORD)
3. Increments values
4. Sets values (DWORD)
5. Closes key

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>
#include <iostream>
using std::cout; using std::endl;

HKEY OpenKey(HKEY hRootKey, wchar_t* strKey)
{
	HKEY hKey;
	LONG nError = RegOpenKeyEx(hRootKey, strKey, NULL, KEY_ALL_ACCESS, &hKey);

	if (nError==ERROR_FILE_NOT_FOUND)
	{
		cout << "Creating registry key: " << strKey << endl;
		nError = RegCreateKeyEx(hRootKey, strKey, NULL, NULL, REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL, &hKey, NULL);
	}

	if (nError)
		cout << "Error: " << nError << " Could not find or create " << strKey << endl;

	return hKey;
}

void SetVal(HKEY hKey, LPCTSTR lpValue, DWORD data)
{
	LONG nError = RegSetValueEx(hKey, lpValue, NULL, REG_DWORD, (LPBYTE)&data, sizeof(DWORD));

	if (nError)
		cout << "Error: " << nError << " Could not set registry value: " << (char*)lpValue << endl;
}

DWORD GetVal(HKEY hKey, LPCTSTR lpValue)
{
	DWORD data;		DWORD size = sizeof(data);	DWORD type = REG_DWORD;
	LONG nError = RegQueryValueEx(hKey, lpValue, NULL, &type, (LPBYTE)&data, &size);

	if (nError==ERROR_FILE_NOT_FOUND)
		data = 0; // The value will be created and set to data next time SetVal() is called.
	else if (nError)
		cout << "Error: " << nError << " Could not get registry value " << (char*)lpValue << endl;

	return data;
}

int main()
{
	static DWORD v1, v2;

	HKEY hKey = OpenKey(HKEY_LOCAL_MACHINE,L"SOFTWARE\\MyCompany");

	v1 = GetVal(hKey, L"Value1");
	v2 = GetVal(hKey, L"Value2");

	v1 += 5;
	v2 += 2;

	SetVal(hKey, L"Value1", v1);
	SetVal(hKey, L"Value2", v2);

	RegCloseKey(hKey);

	return 0;
}

Edit: I should add that to make this work in Windows7 with VS2010 I had to set "Project>Configuration Properties>Linker>Manifest File>UAC Execution Level" to requireAdministrator
Last edited on Jan 2, 2012 at 6:48pm
Jan 2, 2012 at 7:12pm
I don't really have appropriate data to answer your performance questions. I suspect the function calls are fast, but I have never measured them. I do have a BHO in C++ that does logging, and the filename and other logging settings are saved in the registry. Every time the logger is invoked these values are accessed all the way (keys are open, buffers are filled, etc.). I have never seen any serious performance hits due to this.

Worth noting, though, that I would have most likely cached the info once and continued using the data from cache, or at least I would have left the key open, but this is how I inherited the code from the previous programmer and so far I haven't had the need to change this.
Jan 2, 2012 at 9:16pm
Thanks, then I'll leave it open and close it in a destructor.

Cheers!
Topic archived. No new replies allowed.