Hi
I need some help on how to read data values from a REG_MULTI_SZ windows registry string. I understand that each data value is null terminated and there is a another terminator in the end. Thanks.
Hi
I need some help on how to read data values from a REG_MULTI_SZ windows registry string. I understand that each data value is null terminated and there is a another terminator in the end. Thanks.
So exactly what do you want to know? You could do something like this:
That's of course, only one variant of solution.Code:int split_multi_strings(const char *regvalue, char *outputarr[], int maxstrings) { const char *ptr = regvalue; int count, len; for(;;) { len = strlen(ptr); if (len == 0 || count == maxstrings-1) break; outputarr[count] = ptr; count++; ptr += len; } // len != 0 means we didn't get to the end of regvalue, so // we need more space for strings. if (len != 0) return -count; return count; }
Note: I haven't compiled and/or tested the above code, so there may be both syntactical and logical errors in it. It's your task to validate it.
--
Mats
Compilers can produce warnings - make the compiler programmers happy: Use them!
Please don't PM me for help - and no, I don't do help over instant messengers.
Thanks for the quick reply
I have something like this, my registry value is AAA and its data values are XXX BBB
so it the registry it is like
AAA REG_MULTI_SZ XXX BBB
I believe when I run a query using RegQueryValueEx, in memory the above is stored as
xxx\0BBB\0\0.
My basically want to remove BBB from this REG_MULTI_SZ string and write XXX back into teh registry
Couple of questions on the above snippet. What does
"for(; " mean, Also whats should i pass in for maxstrings? Thanks.
I meant for(;
Yes, that's how it is described on the MS web-site at least, so either you, I and the MS website are right, or that's not how it's stored! My bet is that we're right!
So, to write it back again, you need to do the opposite of the splitting function I just posted, build a string from the components, and finish it with an extra zero. Actually, I think the code I posted needs a "ptr += len+1" instead of "ptr += len".
--
Mats
Compilers can produce warnings - make the compiler programmers happy: Use them!
Please don't PM me for help - and no, I don't do help over instant messengers.
for(; ; ) is an infinite loop - same as while(1).
You can disable smilies on the post, but I know what you meant.
--
Mats
Compilers can produce warnings - make the compiler programmers happy: Use them!
Please don't PM me for help - and no, I don't do help over instant messengers.
what does the above "for" statement mean, also what is maxstrings? Thanks buddy!
I've already explained the for-statement (probably just crossing you posting while I was typing). Maxstrings is the number of elements in your outputarray. Note that we're just copying the location of the string inside the original buffer, so you may need to use a different buffer to overwrite the original data. [Although if you just want to remove the LAST entry, you can just put a zero in the first character of that string].
--
Mats
Compilers can produce warnings - make the compiler programmers happy: Use them!
Please don't PM me for help - and no, I don't do help over instant messengers.
Yes it was a cross posting. Sorry, But still do not understand the maxstrings part. In the below
lpData is the data value and lpcbData is the size of the buffer. We do not know the number of actual string or slots until we parse it correct, so how can I pass maxstrings to the function. Can you pls. explain a bit more? I am a newbie, pls. bear with me.
LONG WINAPI RegQueryValueEx(
__in HKEY hKey,
__in_opt LPCTSTR lpValueName,
__reserved LPDWORD lpReserved,
__out_opt LPDWORD lpType,
__out_opt LPBYTE lpData,
__inout_opt LPDWORD lpcbData
);
No, it's not the actual number of strings - it is the number of elements in your array to recieve the split-out values.
So if we have "string1\0string2\0string3\0final strings\0\0" in the registry, then we could do this:
--Code:#define MAXSTRINGS 20 int main() { char buffer[1000]; DWORD size = sizeof(buffer); char *strings[MAXSTRINGS]; LONG res; int count; int i; ... // Code that opens the registry, etc. ... res = RegQueryValueEx(hKey, L"ValueName",0, &type, buffer, &size); if (res > 0) { count = split_multi_strings(buffer, strings, MAXSTRINGS); if (count < 0) { printf("Too many strings in registry, need more space: %d is not enough\n" "displaying what we got so far\n", MAXSTRINGS); count = -count; } for(i = 0; i < count; i++) { printf("%03d: %s\n", i, strings[i]); } } else // deal with errors. ... }
Mats
Compilers can produce warnings - make the compiler programmers happy: Use them!
Please don't PM me for help - and no, I don't do help over instant messengers.
Thanks mat, I will try it out.
Code:#pragma comment ( lib, "advapi32.lib" ) #include <windows.h> #include <stdio.h> #include <tchar.h> int main(void) { HKEY hKey = NULL; DWORD dwReturn = ERROR_SUCCESS; dwReturn = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Services\\DHCP"), 0, KEY_ALL_ACCESS, &hKey ); if( dwReturn == ERROR_SUCCESS ) { DWORD dwSize; dwReturn = RegQueryValueEx( hKey, TEXT("DependOnService"), 0, 0, 0, &dwSize ); if( dwReturn == ERROR_SUCCESS ) { DWORD dwType; LPBYTE lpBuffer = LPBYTE(GlobalAlloc(GPTR, dwSize)); if( lpBuffer == NULL ) { printf("GlobalAlloc failed (%d)\n", GetLastError()); RegCloseKey(hKey); return -1; } dwReturn = RegQueryValueEx( hKey, TEXT("DependOnService"), 0, &dwType, lpBuffer, &dwSize ); if( dwReturn == ERROR_SUCCESS ) { register LPTSTR p = LPTSTR(lpBuffer); for(; *p; p += _tcslen(p) + 1) printf("%s\n",p); } GlobalFree(HGLOBAL(lpBuffer)); } RegCloseKey(hKey); } return 0; }
This isn't reliable, there's no guarantee the returned data is null terminated so you're potentially off into the weeds and dead faster than you can say Steve Irwin. If you don't want to check for proper termination yourself use RegGetValue if you can target Vista, or SHQueryValueEx elsewhere. Another alternative if you're only querying one value is to use SHRegGetUSValue or SHGetValueand forget about all the opening and closing malarky.
Last edited by adeyblue; 12-04-2008 at 09:47 PM.
I'm not sure I understand what you mean by there's no guarantee that a REG_MULTI_SZ will be null terminated. This MSDN link indicates that a REG_MULTI_SZ is null terminated.
EDIT On second thought, I can see how that can possibly happen. For example, an incompetent programmer badly forming a REG_MULTI_SZ string and then writing it out to the key.
EDIT1 So, if you want to code defensively against incompetency in the above example, just increase dwSize by one.
Last edited by BobS0327; 12-04-2008 at 10:41 PM.