views:

96

answers:

1

So I have been stuck on this for a while... thought I got it to work, but it breaks sometimes and I am not sure of the exact reasons...

I am not sure if this matters but I am writing this inside Browser Helper Object (BHO)... Is IE always 32 bit process, no matter whether it is running on 64 and 32 bit OS?

so I want to be able to read from registry, a key that I may need to crate...

I use this function:

if (RegCreateKeyEx(HKEY_CURRENT_USER, L"Software\\ProductName", 0, NULL,
                   REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS | KEY_WOW64_32KEY,
                   NULL, &hk, NULL) == ERROR_SUCCESS)

then I check if the key exist with this:

TCHAR ext_id[20];
DWORD toolbarIdLength;

if(RegQueryValueEx(hk, L"ext_id", NULL, NULL,
                   (LPBYTE)ext_id, &extIdLength) == ERROR_SUCCESS)

if successful then I make sure it is null terminated:

ext_id[extIdLength] = 0;

else I use wininet lib to send the info to my server, assigning new ext_id and I write to registry this value... using this function:

RegSetValueEx(hk, L"ext_id", 0, REG_SZ, (const BYTE *)ext_id, _tcslen(ext_id)*2 + 1);

for some weird reason it was writing only half of the stuff I was passing so I doubled _tcslen(ext_id) and added 1 for safety? Most of the examples I found online do not have that length multiplied by 2, it works for me like this so I left it alone...

seems all this worked properly:

and it worked for my dev_machine: Windows 7 64bit.

tested it on 32 bit Windows 7...

The issue came along on Windows XP IE 6, it did not work , but it seems that if I call RegQueryValueEx function again, it would return the correct value, so I noticed on the next request...

I also noticed that depending on what other string I send over to the server, it would work differently, it may be due to the fact that I am relatively new to C++, (only couple of weeks really in) and I am sure I am doing something really wrong.

Oh I read on msdn that I need to use KEY_WOW64_32KEY, or KEY_WOW64_64KEY, in the flags for opening the registry key depending on situation... but is this really necessary in my situation (BHO for browsers 6.0 to 8.0)

A: 

You have fallen afoul of how windows handles unicode. Dev Studio has a handy switch that lets you toggle between Unicode and Multibyte builds for applications and you are building for Unicode.

The location is Project Properties - Configuration Properties - General - Character Set : Use Unicode Character Set.

The L in front of all your string literals means that the string literal is an array of wchar_t's: L"Software\ProductName".

TCHAR is a macro that means wchar_t when building for unicode and `char1 when building a multibyte character set application.

_tcslen likewise is a MACRO that the msv c-runtine defines as strlen or wcslen depending on the projects selected character set.

Anyway, the crux of the issue is: wcslen returns the number of wchar_t's in the string, and the registry functions expect the number of bytes of data.

This would be the correct way of writing RegSetValueEx such that the Character Switch set would work:

DWORD cch=0;
StrCchLength(ext_id,1024,&cch);
RegSetValueEx(hk, TEXT("ext_id"), 0, REG_SZ, (const BYTE *)ext_id, ( cch + 1) * sizeof(TCHAR));

Note that i've used the StrCchLength API from StrSafe.h instead of strlen, wcslen, lstrlen or related APIs. StrCchLength and related APIs have features that help you write safer code - in this case rather than performing an unbounded write to the registry, ext_id is "clipped" to 1024 characters.

Note: You DO need to be very careful here. Some of the Registry APIs are documented as requiring the byte count to EXCLUDE the terminating zero, RegSetValueEx requires the byte count to include the zero terminator. So I add +1 to the character count of the string THEN multiply by the size of TCHAR to get the number of types.


On reading values - the reason you need to query twice is RegQueryValueEx uses the lpcbData pointer for two purposes - as an input value it specifies the size of the buffer, and as an output value where it returns the number of actual bytes written to the buffer (on success) OR, if the return code is ERROR_MORE_DATA, then the buffer is NOT written, but *lpcbData is set to the number of bytes needed.

TCHAR ext_id[20];
DWORD extIdLength = sizeof (ext_id); // you need to initialize this
LONG err = RegQueryValueEx(hk, TEXT("ext_id"), NULL, NULL, (LPBYTE)ext_id, &extIdLength) ;
if(err == ERROR_MORE_DATA) {
  // you can try again here, using extIdLength to create a new buffer that IS big enough
}
if(err == ERROR_SUCCESS){
  ...
Chris Becke
Thanx for the quick answer.... Does writing to registry have any effect on reading from it? I understand all the points you have made, but I am having problems reading from registry in Windows XP, seems like the only way around it is to open and query the key twice if necessary to get this to work The strangest thing is that when I used AtlEscapeUrl inside the same function the RegQueryValueEx just fails in WindowsXP,but works in Windows7, and when I moved this function out, to the child function, it started working again for both... What is going on here?