Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

RegRead64() and RegWrite64() - no redirect to Wow6432Node


  • Please log in to reply
31 replies to this topic
tomte
  • Members
  • 12 posts
  • Last active: Aug 07 2011 09:02 PM
  • Joined: 12 Aug 2007
This script provides RegRead64() and RegWrite64() functions that do not redirect to Wow6432Node on 64-bit machines.

Registry calls from 32 bit applications running on 64 bit machines are normally intercepted by the system and redirected from HKLM\SOFTWARE to HKLM\SOFTWARE\Wow6432Node. Using these functions you can read the "true" registry on 64 bit machines from AutoHotkey.

; _reg64.ahk ver 0.1 by tomte
; Script for AutoHotkey   ( http://www.autohotkey.com/ )
; 
; Provides RegRead64() and RegWrite64() functions that do not redirect to Wow6432Node on 64-bit machines
; RegRead64() and RegWrite64() takes the same parameters as regular AHK RegRead and RegWrite commands, plus one optional DataMaxSize param for RegRead64()
; 
; RegRead64() can handle the same types of values as AHK RegRead: 
; REG_SZ, REG_EXPAND_SZ, REG_MULTI_SZ, REG_DWORD, and REG_BINARY
; (values are returned in same fashion as with RegRead - REG_BINARY as hex string, REG_MULTI_SZ split with linefeed etc.)
; 
; RegWrite64() can handle REG_SZ, REG_EXPAND_SZ and REG_DWORD only
; 
; Usage: 
; myvalue := RegRead64("HKEY_LOCAL_MACHINE", "SOFTWARE\SomeCompany\Product\Subkey", "valuename")
; RegWrite64("REG_SZ", "HKEY_LOCAL_MACHINE", "SOFTWARE\SomeCompany\Product\Subkey", "valuename", "mystring")
; If the value name is blank/omitted the subkey's default value is used, if the value is omitted with RegWrite64() a blank/zero value is written
; 

RegRead64(sRootKey, sKeyName, sValueName = "", DataMaxSize=1024) {
	HKEY_CLASSES_ROOT	:= 0x80000000	; http://msdn.microsoft.com/en-us/library/aa393286.aspx
	HKEY_CURRENT_USER	:= 0x80000001
	HKEY_LOCAL_MACHINE	:= 0x80000002
	HKEY_USERS			:= 0x80000003
	HKEY_CURRENT_CONFIG	:= 0x80000005
	HKEY_DYN_DATA		:= 0x80000006
	HKCR := HKEY_CLASSES_ROOT
	HKCU := HKEY_CURRENT_USER
	HKLM := HKEY_LOCAL_MACHINE
	HKU	 := HKEY_USERS
	HKCC := HKEY_CURRENT_CONFIG
	
	REG_NONE 				:= 0	; http://msdn.microsoft.com/en-us/library/ms724884.aspx
	REG_SZ 					:= 1
	REG_EXPAND_SZ			:= 2
	REG_BINARY				:= 3
	REG_DWORD				:= 4
	REG_DWORD_BIG_ENDIAN	:= 5
	REG_LINK				:= 6
	REG_MULTI_SZ			:= 7
	REG_RESOURCE_LIST		:= 8

	KEY_QUERY_VALUE := 0x0001	; http://msdn.microsoft.com/en-us/library/ms724878.aspx
	KEY_WOW64_64KEY := 0x0100	; http://msdn.microsoft.com/en-gb/library/aa384129.aspx (do not redirect to Wow6432Node on 64-bit machines)
	KEY_SET_VALUE	:= 0x0002
	KEY_WRITE		:= 0x20006

	myhKey := %sRootKey%		; pick out value (0x8000000x) from list of HKEY_xx vars
	IfEqual,myhKey,, {		; Error - Invalid root key
		ErrorLevel := 3
		return ""
	}
	
	RegAccessRight := KEY_QUERY_VALUE + KEY_WOW64_64KEY
	
	DllCall("Advapi32.dll\RegOpenKeyExA", "uint", myhKey, "str", sKeyName, "uint", 0, "uint", RegAccessRight, "uint*", hKey)	; open key
	DllCall("Advapi32.dll\RegQueryValueExA", "uint", hKey, "str", sValueName, "uint", 0, "uint*", sValueType, "uint", 0, "uint", 0)		; get value type
	If (sValueType == REG_SZ or sValueType == REG_EXPAND_SZ) {
		VarSetCapacity(sValue, vValueSize:=DataMaxSize)
		DllCall("Advapi32.dll\RegQueryValueExA", "uint", hKey, "str", sValueName, "uint", 0, "uint", 0, "str", sValue, "uint*", vValueSize)	; get string or string-exp
	} Else If (sValueType == REG_DWORD) {
		VarSetCapacity(sValue, vValueSize:=4)
		DllCall("Advapi32.dll\RegQueryValueExA", "uint", hKey, "str", sValueName, "uint", 0, "uint", 0, "uint*", sValue, "uint*", vValueSize)	; get dword
	} Else If (sValueType == REG_MULTI_SZ) {
		VarSetCapacity(sTmp, vValueSize:=DataMaxSize)
		DllCall("Advapi32.dll\RegQueryValueExA", "uint", hKey, "str", sValueName, "uint", 0, "uint", 0, "str", sTmp, "uint*", vValueSize)	; get string-mult
		sValue := ExtractData(&sTmp) "`n"
		Loop {
			If (errorLevel+2 >= &sTmp + vValueSize)
				Break
			sValue := sValue ExtractData( errorLevel+1 ) "`n" 
		}
	} Else If (sValueType == REG_BINARY) {
		VarSetCapacity(sTmp, vValueSize:=DataMaxSize)
		DllCall("Advapi32.dll\RegQueryValueExA", "uint", hKey, "str", sValueName, "uint", 0, "uint", 0, "str", sTmp, "uint*", vValueSize)	; get binary
		sValue := ""
		SetFormat, integer, h
		Loop %vValueSize% {
			hex := SubStr(Asc(SubStr(sTmp,A_Index,1)),3)
			StringUpper, hex, hex
			sValue := sValue hex
		}
		SetFormat, integer, d
	} Else {				; value does not exist or unsupported value type
		DllCall("Advapi32.dll\RegCloseKey", "uint", hKey)
		ErrorLevel := 1
		return ""
	}
	DllCall("Advapi32.dll\RegCloseKey", "uint", hKey)
	return sValue
}

RegWrite64(sValueType, sRootKey, sKeyName, sValueName = "", sValue = "") {
	HKEY_CLASSES_ROOT	:= 0x80000000	; http://msdn.microsoft.com/en-us/library/aa393286.aspx
	HKEY_CURRENT_USER	:= 0x80000001
	HKEY_LOCAL_MACHINE	:= 0x80000002
	HKEY_USERS			:= 0x80000003
	HKEY_CURRENT_CONFIG	:= 0x80000005
	HKEY_DYN_DATA		:= 0x80000006
	HKCR := HKEY_CLASSES_ROOT
	HKCU := HKEY_CURRENT_USER
	HKLM := HKEY_LOCAL_MACHINE
	HKU	 := HKEY_USERS
	HKCC := HKEY_CURRENT_CONFIG
	
	REG_NONE 				:= 0	; http://msdn.microsoft.com/en-us/library/ms724884.aspx
	REG_SZ 					:= 1
	REG_EXPAND_SZ			:= 2
	REG_BINARY				:= 3
	REG_DWORD				:= 4
	REG_DWORD_BIG_ENDIAN	:= 5
	REG_LINK				:= 6
	REG_MULTI_SZ			:= 7
	REG_RESOURCE_LIST		:= 8

	KEY_QUERY_VALUE := 0x0001	; http://msdn.microsoft.com/en-us/library/ms724878.aspx
	KEY_WOW64_64KEY := 0x0100	; http://msdn.microsoft.com/en-gb/library/aa384129.aspx (do not redirect to Wow6432Node on 64-bit machines)
	KEY_SET_VALUE	:= 0x0002
	KEY_WRITE		:= 0x20006
	
	myhKey := %sRootKey%			; pick out value (0x8000000x) from list of HKEY_xx vars
	myValueType := %sValueType%		; pick out value (0-8) from list of REG_SZ,REG_DWORD etc. types
	IfEqual,myhKey,, {		; Error - Invalid root key
		ErrorLevel := 3
		return ErrorLevel
	}
	IfEqual,myValueType,, {	; Error - Invalid value type
		ErrorLevel := 2
		return ErrorLevel
	}
	
	RegAccessRight := KEY_QUERY_VALUE + KEY_WOW64_64KEY + KEY_WRITE
	
	DllCall("Advapi32.dll\RegCreateKeyExA", "uint", myhKey, "str", sKeyName, "uint", 0, "uint", 0, "uint", 0, "uint", RegAccessRight, "uint", 0, "uint*", hKey)	; open/create key
	If (myValueType == REG_SZ or myValueType == REG_EXPAND_SZ) {
		vValueSize := StrLen(sValue) + 1
		DllCall("Advapi32.dll\RegSetValueExA", "uint", hKey, "str", sValueName, "uint", 0, "uint", myValueType, "str", sValue, "uint", vValueSize)	; write string
	} Else If (myValueType == REG_DWORD) {
		vValueSize := 4
		DllCall("Advapi32.dll\RegSetValueExA", "uint", hKey, "str", sValueName, "uint", 0, "uint", myValueType, "uint*", sValue, "uint", vValueSize)	; write dword
	} Else {		; REG_MULTI_SZ, REG_BINARY, or other unsupported value type
		ErrorLevel := 2
	}
	DllCall("Advapi32.dll\RegCloseKey", "uint", hKey)
	return ErrorLevel
}

ExtractData(pointer) {  ; http://www.autohotkey.com/forum/viewtopic.php?p=91578#91578 SKAN
	Loop {
			errorLevel := ( pointer+(A_Index-1) )
			Asc := *( errorLevel )
			IfEqual, Asc, 0, Break ; Break if NULL Character
			String := String . Chr(Asc)
		}
	Return String
}

; Thanks Chris, Lexikos and SKAN
; http://www.autohotkey.com/forum/topic37710-15.html
; http://www.autohotkey.com/forum/viewtopic.php?p=235522


afranco
  • Members
  • 1 posts
  • Last active: Oct 12 2009 09:23 PM
  • Joined: 12 Oct 2009
That is wonderful, it solve 1/2 of my needs.
I am also looking for a loop (registry) supporting the 64 bit registry. Anybody? thanks :D

twigdulla17
  • Members
  • 1 posts
  • Last active: Apr 04 2010 01:32 AM
  • Joined: 18 Mar 2010
Here is a small example of the registry redirector:
If you access the key HKEY_LOCAL_MACHINE\SOFTWARE\MyApp\Settings from a 64-bit app, you really opening this node. If you open this node from a 32-bit app, you are transparently redirected to HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\MyApp\Setting.
Collapse

#include <windows.h>

#include <stdio.h>

#include <tchar.h>

#pragma comment(lib, "Advapi32.lib")
int _tmain()
{
LONG lRet;
HKEY hKey;
// Open the key in the default-view

lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE,

_T("SOFTWARE\\MyApp\\MySettings"),
0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
if(lRet == ERROR_SUCCESS)
{
#if _M_IX86
TCHAR szValue[] = _T("x86");
RegSetValueEx(hKey, _T("AppType"), 0, REG_SZ,
(const BYTE*) szValue,
(DWORD) (_tcslen(szValue)+sizeof(TCHAR))*sizeof(TCHAR));
#else
TCHAR szValue[] = _T("x64 / IA64");
RegSetValueEx(hKey, _T("AppType"), 0, REG_SZ,
(const BYTE*) szValue,
(DWORD) (_tcslen(szValue)+sizeof(TCHAR))*sizeof(TCHAR));
#endif
RegCloseKey(hKey);
}
return 0;
}

After executing this example as 32-bit 'and' 64-bit application, you have created two separate registry keys. One containing the "x86" value and the other containing the "x64 / IA64" value.
indianapolis web design

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
I need RegRead64(), but I can't get it to work on my Win7 x64.

This call fails ALWAYS! hKey is always 0 after the call.
DllCall("Advapi32.dll\RegOpenKeyExA", "uint", myhKey, "str", sKeyName, "uint", 0, "uint", RegAccessRight, "uint*", hKey)   ; open key
(BTW, it might be a good idea to check it, and return an ErrorLevel of 4 when it fails.)

I've tried everything, including reading keys in non-protected area of the registry, running the script as Administrator, modifying the code, but to no avail.

Can you confirm that that function is supposed to work under Win7, or is it specific to Vista or XP?

Here is an example of what I've used to check the function:
root  = HKEY_CURRENT_USER
key   = Console
value = ColorTable01
RegRead, key, %root%, %key%, %value%
key64 := RegRead64(root, key, value)
msgbox key = %key%`nkey64 = %key64%
the MsgBox shows the key retrieved by the standard AHK RegRead command, but of course nothing for RegRead64().

Someone can help?


P.S.: I second afranco's request. It would be nice to have also a function to browse the registry tree in x64 mode.

tomte
  • Members
  • 12 posts
  • Last active: Aug 07 2011 09:02 PM
  • Joined: 12 Aug 2007
I haven't had a chance to test on Win7 but I'd take a guess that... ;-)

This works:
root  = HKEY_CURRENT_USER
rkey   = Console
value = ColorTable01
RegRead, key, %root%, %rkey%, %value%
key64 := RegRead64(root, rkey, value)
msgbox key = %key%`nkey64 = %key64%

And this doesn't:
root  = HKEY_CURRENT_USER
key   = Console
value = ColorTable01
RegRead, key, %root%, %key%, %value%
key64 := RegRead64(root, key, value)
msgbox key = %key%`nkey64 = %key64%

(the RegRead line is overwriting your key variable so RegRead64() is fed the wrong key)

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
Oops, that's right! But that code snipped is only something I've written to quickly test the function. In my real program, I haven't made the same error. And anyway, even after having fixed the bug or using your code, the problem persists.

Trust me, there is really something that doesn't work in RegRead64().
(I haven't checked RegWrite64() because I don't need it, but I'm almost sure it has a similar problem.)

BTW, I forgot to say that I use AutoHotkey_Lw v1.0.48.05.L51, if that makes any difference.

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007

BTW, I forgot to say that I use AutoHotkey_Lw v1.0.48.05.L51, if that makes any difference.

Yeah! That's the problem!

The function works fine under the regular AutoHotkey, but fails under AHK_L. Pity, as I need AHK_L for the unicode support and the Objects.

[EDIT]
OK, the solution is simple! I should have read the AHK_L doc before posting here.

Under AHK_Lw (unicode build), simply replace "str" by "AStr" in all DLL calls. I still have to check if the returned value is correct when it's a string (as my example retrieves an integer), but I guess it will be OK.

[EDIT2]
No, that doesn't work. See my next post for the correct solution.

tomte
  • Members
  • 12 posts
  • Last active: Aug 07 2011 09:02 PM
  • Joined: 12 Aug 2007
Ah - good find. Thanks for sharing the solution.

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
Hum, the fix in my previous post doesn't work when a string is retrieved (such as a REG_SZ value type).

The correct fix for AHK_Lw (unicode build) is this one:

Do not change the "str" arguments as explained in my previous post. It's not necessary.

Replace ExA by ExW at the end of all function names in all DLLcalls. (Only RegCloseKey doesn't need to be modified.)

You might also want to increase the default value of the DataMaxSize argument in RegRead64() from 1024 to 2048, to take the "double size" of unicode strings into account.

fincs
  • Moderators
  • 1662 posts
  • Last active:
  • Joined: 05 May 2007

Replace ExA by ExW at the end of all function names in the calls. (Only RegCloseKey doesn't need to be modified.)


Better yet, replace ExA by just Ex to make it work on both AutoHotkey_L builds.

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007

Better yet, replace ExA by just Ex to make it work on both AutoHotkey_L builds.

Oh, yes, thanks for the tip.
But it I've understood correctly, when the A or W extension is not present, AHK_L tries both functions. Is it right? In that case, it might take longer to execute it. Right?
Or does it simply append the correct extension before calling the right function?

fincs
  • Moderators
  • 1662 posts
  • Last active:
  • Joined: 05 May 2007
It does append the correct extension.

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
Thanks.

I have another question. Can I use these RegRead64() and RegWrite64() functions under an x86 version of Windows? I suppose that the same DLL exist, and that the KEY_WOW64_64KEY flag is simply ignored on non-64bit systems. Am I right? (Unfortunately, I don't have x86 OSses here to test.)

fincs
  • Moderators
  • 1662 posts
  • Last active:
  • Joined: 05 May 2007
I think the flag is indeed ignored.

tomte
  • Members
  • 12 posts
  • Last active: Aug 07 2011 09:02 PM
  • Joined: 12 Aug 2007
Correct - the function works fine on 32bit machines as well.