On Sun, 01 Apr 2001, you wrote:
At 01:59 PM 31/03/2001 +0100, you wrote:
<snip> >Compiling and running Winemine under Windows 95 this problem doesn't occur. >Win95 truncates the value at the first null.
Under NT4 SP6, if I write (for example) '47' + 0 + 13 bytes of garbage, I get exactly that when querying with the same buffer length (16). If I use a longer buffer, one binary 0 is appended. If I use a shorter buffer, nothing is copied and the function does not succeed (ERROR_MORE_DATA).
Of course under Regedit the garbage is not displayed; regedit displays only '47' in this case.
I've found time to do some more digging, but I'm still stumped.
This is the trace from WineMine saving one parameter in the registry (-debugmsg +relay,+reg):
Call advapi32.248: RegSetValueExA(00000038,4038cae0 "Xpos",00000000,00000001,405e66a0,00000010) ret=40388dc8 fs=008f Call kernel32.643: MultiByteToWideChar(00000000,00000000,405e66a0 "3",00000010,00000000,00000000) ret=407c4fe9 fs=008f Ret kernel32.643: MultiByteToWideChar() retval=00000010 ret=407c4fe9 fs=008f Call kernel32.553: HeapAlloc(40390000,00000000,00000020) ret=407c4fff fs=008f Ret kernel32.553: HeapAlloc() retval=403d62fc ret=407c4fff fs=008f Call kernel32.643: MultiByteToWideChar(00000000,00000000,405e66a0 "3",00000010,403d62fc,00000010) ret=407c5023 fs=008f Ret kernel32.643: MultiByteToWideChar() retval=00000010 ret=407c5023 fs=008f Call ntdll.419: RtlInitAnsiString(405e658c,4038cae0 "Xpos") ret=407c5038 fs=008f Ret ntdll.419: RtlInitAnsiString() retval=00000000 ret=407c5038 fs=008f Call ntdll.281: RtlAnsiStringToUnicodeString(40113578,405e658c,00000000) ret=407c504d fs=008f Ret ntdll.281: RtlAnsiStringToUnicodeString() retval=00000000 ret=407c504d fs=008f Call ntdll.230: NtSetValueKey(00000038,40113578,00000000,00000001,403d62fc,00000020) ret=407c5067 fs=008f trace:reg:NtSetValueKey (0x38,L"Xpos",1,0x403d62fc,32) Ret ntdll.230: NtSetValueKey() retval=00000000 ret=407c5067 fs=008f Call kernel32.559: HeapFree(40390000,00000000,403d62fc) ret=407c5083 fs=008f Ret kernel32.559: HeapFree() retval=00000001 ret=407c5083 fs=008f Call ntdll.466: RtlNtStatusToDosError(00000000) ret=407c5089 fs=008f Ret ntdll.466: RtlNtStatusToDosError() retval=00000000 ret=407c5089 fs=008f Ret advapi32.248: RegSetValueExA() retval=00000000 ret=40388dc8 fs=008f
So the 16-byte buffer (containing the character "3", a null, and 14 bytes of garbage) has been converted into a 32-byte unicode string and saved. Good. Inside the registry this looks like:
"Xpos"="3\0\0\0`\x00ca7@\0\0\0\0\0\0\0@"
Now if we read that value back in this is what happens:
Call advapi32.236: RegQueryValueExA(00000034,4038cae0 "Xpos",00000000,405e6970,405e697c,405e6974) ret=40388a38 fs=008f trace:reg:RegQueryValueExA (0x34,"Xpos",(nil),0x405e6970,0x405e697c,0x405e6974=16) Call ntdll.419: RtlInitAnsiString(405e6764,4038cae0 "Xpos") ret=407c5565 fs=008f Ret ntdll.419: RtlInitAnsiString() retval=00000000 ret=407c5565 fs=008f Call ntdll.281: RtlAnsiStringToUnicodeString(40113578,405e6764,00000000) ret=407c557a fs=008f Ret ntdll.281: RtlAnsiStringToUnicodeString() retval=00000000 ret=407c557a fs=008f Call ntdll.177: NtQueryValueKey(00000034,40113578,00000002,405e676c,00000100,405e6760) ret=407c55b0 fs=008f trace:reg:NtQueryValueKey (0x34,L"Xpos",2,0x405e676c,256) Ret ntdll.177: NtQueryValueKey() retval=00000000 ret=407c55b0 fs=008f Call kernel32.889: WideCharToMultiByte(00000000,00000000,405e6778 L"3",00000011,00000000,00000000,00000000,00000000) ret=407c56c9 fs=008f Ret kernel32.889: WideCharToMultiByte() retval=00000011 ret=407c56c9 fs=008f Call ntdll.466: RtlNtStatusToDosError(80000005) ret=407c57be fs=008f Ret ntdll.466: RtlNtStatusToDosError() retval=000000ea ret=407c57be fs=008f Ret advapi32.236: RegQueryValueExA() retval=000000ea ret=40388a38 fs=008f
RegQueryValueEx maintains that there are 17 characters and since they won't fit in the buffer the function aborts.
Incidentally, the "null-terminate if the user forgot" trick is carried out both in RegSetValueEx *and* RegQueryValueEx. Would not once be enough?