Reading registry on Windows 64
Archives Forums/Win32 Discussion/Reading registry on Windows 64
| ||
Global valorestr:String temp_proc:Tprocess = CreateProcess("c:\windows\sysnative\reg.exe QUERY "+Chr(34)+"HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\layers"+Chr(34),1) ttt=0 While temp_proc.status() If temp_proc.pipe.ReadAvail() valorestr= temp_proc.pipe.ReadLine() If valorestr If Len(valorestr)>5 Print ttt+" "+valorestr ttt:+1 EndIf EndIf EndIf Wend try to add these keys to registry... (just to try to read something) Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers] "C:\\Program Files (x86)\\Jasc Software Inc\\Paint Shop Pro 9\\Paint Shop Pro 9.exe"="FaultTolerantHeap" "C:\\BlitzMax\\tmp\\untitled1.debug.exe"="FaultTolerantHeap" "C:\\Program Files (x86)\\test\\Paint Shop Pro 9\\test.exe"="AAAAAAAAA" i received.... Semetimes.. NOTHING.. (no reading) Other times (always) .. just first string... but after that i have a EXCEPTION_ACCESS_VIOLATION and debug mode doesn't return to code to explain what appened... I'currently using windows 10 but i've the same issues on other Windows 8 systems. (always 64 bit) P.S. the code is working (try to remove "LAYERS" and read: HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags .. ) everything is working but strangely the reading stops at CUSTOM key (on DEBUG MODE) ... no reaching LAYERS.. but can read everything if on RELEASE MODE. |
| ||
there's some funky redirecting going on for 32-bit apps (like Blitzmax executables) under 64-bit windows. e.g. instead of: HKLM\Software\Microsoft\WindowsNT\CurrentVersion it gets redirected to: HKLM\Software\WOW6432Node\Microsoft\WindowsNT\CurrentVersion If you get inconsistent results, perhaps check for 64-bit windows and if you detect it, attempt reading the WOW6432Node contents instead of the 64-bit branches. |
| ||
i'm reading the SYSNATIVE (64 bit real key) using the "sysnative\reg.exe" (if i use the SYSTEM32\reg.exe" i will read the WOW content) this is not the issue.. i thing this is a Blitzmax Bug... on DEBUG MODE and on RELEASE MODE there are 2 different results (and on LAYERS KEY.. BOTH CRASHES WITHOUT EXPLANATIONS) if i change the code with: Local temp_proc:Tprocess = CreateProcess("c:\windows\sysnative\reg.exe QUERY "+Chr(34)+"HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\layers"+Chr(34),1) While temp_proc.status() If temp_proc.pipe.ReadAvail() Print "pipe: " + temp_proc.pipe.ReadString(20) Wend i can read everything (last line is cutted because is out of 20 chars) but with a 20 chars layout... (and no final characters) and yep.. i tried to read a single char (a do a join of chars) .. but reading stops at first line. Executing:untitled1.exe pipe: HKEY_LOCAL_MACHINE pipe: \SOFTWARE\Microsoft\ pipe: Windows NT\CurrentVe pipe: rsion\AppCompatFlags pipe: \layers C:\Prog pipe: ram Files (x86)\Jasc pipe: Software Inc\Paint pipe: Shop Pro 9\Paint Sho pipe: p Pro 9.exe REG_S pipe: Z FaultTolerantHe pipe: ap C:\Program F pipe: iles (x86)\test\Pain pipe: t Shop Pro 9\test.ex pipe: e REG_SZ CAZZO pipe: ZLOOOAA C:\Blit pipe: zMax\tmp\untitled1.e pipe: xe REG_SZ Faul Error reading from stream Process complete ANOTHER STRANGE EXAMPLE.... if i add a delay(1) on the code... i can't receive ANYTHING. Local temp_proc:Tprocess = CreateProcess("c:\windows\sysnative\reg.exe QUERY "+Chr(34)+"HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags"+Chr(34),1) While temp_proc.status() If temp_proc.pipe.ReadAvail() valorestr$= temp_proc.pipe.ReadLine() Delay(1) 'this delay do the thing... NO RESULT JUST 3 EMPTY STRINGS. Print VALORESTR$ EndIf Wend this is a timing issue i think... the stream from the createprocess if too fast... and can be lost on faster machines... (o something like that) |
| ||
FWIW, it's also possible to query the registry directly from within blitzmax, without having to resort to external processes. There's examples in the code archives and other old forum posts, e.g.: http://www.blitzbasic.com/codearcs/codearcs.php?code=1991 Generally it seems like a bad idea to hardcode paths to external dependencies like you did -- for example, c:\windows\sysnative\reg.exe doesn't exist on my 64 bit Windows 10 installation. it has c:\windows\system32\reg.exe (64 bit) and c:\windows\syswow64\reg.exe (presumably 32 bit) Either way, hardcoding the location is bound to cause issues, especially when factoring in non-English windows versions which often have localized folder names that may differ from the US edition. |
| ||
Xlsior, the SYSNATIVE folder was introduced by microsoft to add compatibility (like the KEY_WOW64_64KEY flag) to 64bit to older 32 bit applications... the SYSNATIVE folder is redirected to SYSTEM32 (and not syswow64) directly from the OS (windows VISTA/7/8/8.1/10) you can try to add an executable to system32 .. and launch it using the sysnative virtual folder. FOR THE REGISTRY CODE POSTED: i've used the standard API for the 32 Bit reading (and works fine) .. for 64 bit use of that APIs (for some REGISTRY KEYS ENUMERATIONS --> yellow folders on left of regedit) i've added the: KEY_WOW64_64KEY = 0x0100 parameter but for NOW ... i'n not able to read VALUES on RIGHT part of regedit (like these layers values) if anyone can fix the ENUMERATEVALUES Function with KEY_WOW64_64KEY i'll be very thankful :) (i've tried but i've just ported to 64 bit the ENUMERATEKEYS) |
| ||
Xlsior, the SYSNATIVE folder was introduced by microsoft to add compatibility (like the KEY_WOW64_64KEY flag) to 64bit to older 32 bit applications... the SYSNATIVE folder is redirected to SYSTEM32 (and not syswow64) directly from the OS (windows VISTA/7/8/8.1/10) Ok, hadn't heard of that one -- When calling it through blitzmax it appears that that sysnative path does resolve, when I try to invoke c:\windows\sysnative\reg.exe from the windows command prompt it does not, returns a "The system cannot find the path specified" |
| ||
the only way seems to "port"Function RegEnumValue:Long(hKey:Int,idx:Int,ValueName:Byte Ptr,NameSize:Byte Ptr,Reserved:Int,nType:Byte Ptr,ValueBytes:Byte Ptr,ValueSize:Byte Ptr)="RegEnumValueA" to the 64 BIT version including the "KEY_WOW64_64KEY = 0x0100" on this 32 bit function ... WHERE I NEED TO PLACE THE FLAG??? ' enumerates the keys contained in the passed subkey And returns them as a delimited String in ' the format: KEY=VALUE|KEY=VALUE|KEY=VALUE Function reg_enumvalues:String(RegKey:Int,SubKey:String,delim:String="|",types=False) Local cRetVal:String="",key:String="",val:String="" Local keybank:TBank=CreateBank(100),keybanksize:TBank=CreateBank(4),valbank:TBank=CreateBank(100),valbanksize:TBank=CreateBank(4),typebank:TBank=CreateBank(4) Local char:Int=0,nIdx:Int=0,nType:Int=0 ' open the key Local hKey=reg_openkey(RegKey,SubKey:String) If hKey<>-1 ' read in the values Repeat ' init the banks PokeInt(typebank,0,0) PokeInt(valbanksize,0,100) PokeInt(keybanksize,0,100) ' clear out the temp values key:String="" val:String="" If RegEnumValue(hKey,nIdx,BankBuf(keybank),BankBuf(keybanksize),0,BankBuf(typebank),BankBuf(valbank),BankBuf(valbanksize))<>REG_ERROR_EOF nType=PeekInt(typebank,0) ' tack on the delimiter If cRetVal:String<>"" cRetVal:String=cRetVal:String+delim:String EndIf ' build the key name For char=0 To PeekInt(keybanksize,0)-1 If PeekByte(keybank,char)=0 Then Exit key:String=key:String+Chr(PeekByte(keybank,char)) Next Select nType ' read in a String Or binary value Case REG_SZ, REG_BINARY ' build the value For char=0 To PeekInt(valbanksize,0)-1 If PeekByte(valbank,char)=0 Then Exit val:String=val:String+Chr(PeekByte(valbank,char)) Next ' read in an integer Case REG_DWORD val:String=PeekInt(valbank,0) End Select If types cRetVal:String=(cRetVal:String+PeekInt(typebank,0)+"'"+key:String+"="+val:String) Else cRetVal:String=(cRetVal:String+key:String+"="+val:String) EndIf Else Exit EndIf nIdx=nIdx+1 Forever reg_closekey(hKey) EndIf typebank = Null valbank = Null valbanksize = Null keybank = Null keybanksize = Null Return cRetVal:String End Function |