How to get and display registry entries

Windows specific questions.
codeFoil
Posts: 256
Joined: Dec 22, 2011 4:45
Location: United States
Contact:

Post by codeFoil »

palahoot wrote:
the problem with the shell commmand is fixed, it appears that the comspec ev was set to: c:\windows\system32\cmd.exe /f:on /e:on so i reverted it to: c:\windows\system32\cmd.exe with no parameters, rebooted and now its working on my windows xp box.
That makes sense now. The entire value of the environment variable was being passed as a file name, which obviously doesn't exist. Fortunately, you shouldn't need those options on CMD.EXE's command line. /e controls command interpreter extensions, which are on by default. /f control file directory and file name completion (very useful), which is off by default, but you can control both through registry settings.
Cherry
Posts: 358
Joined: Oct 23, 2007 12:06
Location: Austria
Contact:

Post by Cherry »

Why do you need "Shell" at all?

It's easier and faster not to call external programs for every task^^

registry.bi

Code: Select all

#Include Once "win/winreg.bi"
#Define REG_KEY_NOT_EXIST "REG_KEY_NOT_EXIST"
#Define REG_KEY_INVALID "REG_KEY_INVALID"
Type RegLib
	Declare Constructor(root As HKEY, Key As String, create As Boolean = FALSE)
	Declare Destructor()
	Declare Function createMe() As Boolean
	Declare Function deleteMe() As Boolean
	Declare Function getValue(v As String) As String
	Declare Function setValue(v As String, s As String) As Boolean
	Declare Function getDwValue(v As String, errcheck As Boolean = FALSE) As Integer
	Declare Function setDwValue(v As String, s As Integer) As Boolean
	Declare Property default() As String
	Declare Property default(s As String)
	exists As Boolean
	root As HKEY
	key As String
	
	Private:
	rkey As HKEY
End Type

Constructor RegLib(root As HKEY, key As String, create As Boolean = FALSE)
	this.root = root
	this.key = key
	If RegOpenKeyEx(root, StrPtr(key), 0, KEY_ALL_ACCESS, @this.rkey) <> ERROR_SUCCESS Then
		If create Then
			createMe()
		Else
			exists = FALSE
		EndIf
	Else
		exists = TRUE
	EndIf
End Constructor

Destructor RegLib()
	RegCloseKey(rkey)
End Destructor

Function RegLib.createMe() As Boolean
	If RegCreateKeyEx(root, StrPtr(key), 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, @rkey, 0) = ERROR_SUCCESS Then
		exists = TRUE
	Else
		exists = FALSE
	EndIf
	Return exists
End Function

Function RegLib.deleteMe() As Boolean
	If RegDeleteKey(root, StrPtr(key)) = ERROR_SUCCESS Then
		exists = FALSE
		Return TRUE
	Else
		exists = TRUE
		Return FALSE
	End If
End Function

Function RegLib.getValue(v As String) As String
	If exists = FALSE Then Return REG_KEY_NOT_EXIST
	Dim out_ As ZString * 1024
	Dim l As DWORD = 512
	Dim t As DWORD
	If RegQueryValueEx(rkey, StrPtr(v), NULL, @t, @out_, @l) <> ERROR_SUCCESS OrElse (t <> REG_SZ AndAlso t <> REG_EXPAND_SZ) Then
		Return REG_KEY_INVALID
	EndIf
	out_[512 - 1] = 0
	Return out_
End Function

Function RegLib.setValue(v As String, s As String) As Boolean
	If exists = FALSE Then Return FALSE
	Return RegSetValueEx(rkey, StrPtr(v), 0, REG_SZ, StrPtr(s), Len(s) + 1) = ERROR_SUCCESS
End Function

Function RegLib.getDwValue(v As String, errcheck As Boolean = FALSE) As Integer
	If exists = FALSE Then Return IIf(errcheck, -1, 0)
	Dim out_ As Integer
	Dim l As DWORD = 4
	Dim t As DWORD
	If RegQueryValueEx(rkey, StrPtr(v), NULL, @t, @out_, @l) <> ERROR_SUCCESS OrElse (t <> REG_DWORD) Then
		Return IIf(errcheck, -1, 0)
	EndIf
	Return out_
End Function

Function RegLib.setDwValue(v As String, s As Integer) As Boolean
	If exists = FALSE Then Return FALSE
	Return RegSetValueEx(rkey, StrPtr(v), 0, REG_DWORD, @s, 4) = ERROR_SUCCESS
End Function

Property RegLib.default() As String
	Return getValue("")
End Property

Property RegLib.default(s As String)
	setValue("", s)
End Property

Type RegKey As RegLib
example.bas

Code: Select all

#Include "registry.bi"

Var reg = RegKey(HKEY_CURRENT_USER, "Control Panel\Desktop")
Print reg.getValue("Wallpaper")
Sleep
Best regards,
Cherry
palahoot
Posts: 131
Joined: Dec 15, 2011 21:55

Re: How to get and display registry entries

Post by palahoot »

Hey Cherry,

Many thanks. but im getting error's when i do the quick compile as well as the command line compile Here is the output:

Code: Select all

C:\Program Files\FreeBASIC\fbc -s console "FbTemp.bas"
C:\Program Files\FreeBASIC\inc\win\winreg.bi(47) error 14: Expected identifier, found 'LPSTR' in 've_valuename as LPSTR'
C:\Program Files\FreeBASIC\inc\win\winreg.bi(48) error 14: Expected identifier, found 'DWORD' in 've_valuelen as DWORD'
C:\Program Files\FreeBASIC\inc\win\winreg.bi(49) error 14: Expected identifier, found 'DWORD' in 've_valueptr as DWORD'
C:\Program Files\FreeBASIC\inc\win\winreg.bi(50) error 14: Expected identifier, found 'DWORD' in 've_type as DWORD'
C:\Program Files\FreeBASIC\inc\win\winreg.bi(57) error 14: Expected identifier, found 'LPWSTR' in 've_valuename as LPWSTR'
C:\Program Files\FreeBASIC\inc\win\winreg.bi(58) error 14: Expected identifier, found 'DWORD' in 've_valuelen as DWORD'
C:\Program Files\FreeBASIC\inc\win\winreg.bi(59) error 14: Expected identifier, found 'DWORD' in 've_valueptr as DWORD'
C:\Program Files\FreeBASIC\inc\win\winreg.bi(60) error 14: Expected identifier, found 'DWORD' in 've_type as DWORD'
C:\Program Files\FreeBASIC\inc\win\winreg.bi(66) error 56: Illegal specification, at parameter 1 of RegCloseKey() in 'declare function RegCloseKey alias "RegCloseKey" (byval as HKEY) as LONG'
C:\Program Files\FreeBASIC\inc\win\winreg.bi(67) error 56: Illegal specification, at parameter 1 of RegFlushKey() in 'declare function RegFlushKey alias "RegFlushKey" (byval as HKEY) as LONG'
C:\Program Files\FreeBASIC\inc\win\winreg.bi(67) error 123: Too many errors, exiting
i cheked this path and the library exists there: C:\Program Files\FreeBASIC\inc\win\winreg.bi

any thoughts?
codeFoil
Posts: 256
Joined: Dec 22, 2011 4:45
Location: United States
Contact:

Re: How to get and display registry entries

Post by codeFoil »

palahoot wrote:Hey Cherry,

Many thanks. but im getting error's when i do the quick compile as well as the command line compile

i cheked this path and the library exists there: C:\Program Files\FreeBASIC\inc\win\winreg.bi

any thoughts?
winreg.bi depends on type definitions declared in windef.bi.
Change "win\Winregbi" to "windows.bi".

Windows.bi includes almost all the header files usually required to work with the Win32 API.
Cherry's example works if Windows.bi is included prior to including his registy.bi. I assume he only included winreg.bi to cut down compile time.

See http://msdn.microsoft.com/en-us/library ... S.85).aspx for a list of data types used by the Win32 API.
palahoot
Posts: 131
Joined: Dec 15, 2011 21:55

Re: How to get and display registry entries

Post by palahoot »

codeFoil wrote: winreg.bi depends on type definitions declared in windef.bi.
Change "win\Winregbi" to "windows.bi".
Windows.bi includes almost all the header files usually required to work with the Win32 API.
Cherry's example works if Windows.bi is included prior to including his registy.bi. I assume he only included winreg.bi to cut down compile time.
See http://msdn.microsoft.com/en-us/library ... S.85).aspx for a list of data types used by the Win32 API.
and indeed that does make the error's go away, many thanks for that fix. So now when i make the change to his program like so:

Code: Select all

#Include "registry.bi"

Var reg = RegKey(HKEY_CURRENT_USER, "Software\SPAR")
Print reg.getValue("Return1")
Sleep
the path HKCU\Software\SPAR\Return1 does exist in the registry (i can get to the value with other methods) but when i run the new program, then i get the following error: REG_KEY_INVALID

The reg key value type is REG_SZ and as you can see, it is just a standard string. what changes do i have to make to the program above to get it to accept the type as a REG_SZ
codeFoil
Posts: 256
Joined: Dec 22, 2011 4:45
Location: United States
Contact:

Re: How to get and display registry entries

Post by codeFoil »

palahoot wrote: the path HKCU\Software\SPAR\Return1 does exist in the registry (i can get to the value with other methods) but when i run the new program, then i get the following error: REG_KEY_INVALID

The reg key value type is REG_SZ and as you can see, it is just a standard string. what changes do i have to make to the program above to get it to accept the type as a REG_SZ
First, make certain that your registry value actually exists. Check the spelling and the case.
Second, double check the registry value type.

From what I can see, Cherry's object method returns REG_KEY_INVALID if the underlying call to RegQueryValueEx returns anything other than ERROR_SUCCESS, or the value in the registry is not of type REG_SZ or REG_EXPAND_SZ. RegQueryValueEx may be returning an error code.
If your value does indeed exist, and it is of type REG_SZ, then the most likely reason that the call might fail is that the size of the string is larger than the size specified in the API call. Cherry's code specifies a maximum of 512 bytes, and declares a 1024 byte buffer to hold the returned string.
I have modified Cherry's code to output the return value of RegQueryValueEx and the byte count of the buffer required as reported by the API.
I have NOT tested this code.

Code: Select all

'****Cherry's original function modified for testing
Function RegLib.getValue(v As String) As String
   If exists = FALSE Then Return REG_KEY_NOT_EXIST
   Dim out_ As ZString * 1024
   Dim l As DWORD = 512
   Dim t As DWORD
   '***  CHANGES BEGIN HERE
   Dim as Long returnStatus = RegQueryValueEx( rkey     ,_
                                               StrPtr(v),_
                                               NULL     ,_
                                               @t       ,_
                                               @out_    ,_
                                               @l        )
   If returnStatus <> ERROR_SUCCESS _ 
   OrElse (t <> REG_SZ AndAlso t <> REG_EXPAND_SZ) _
   Then
      Print returnStatus  'These lines are for debugging,
      Print l                    'and may be removed.
   '*** CHANGES END HERE
      Return REG_KEY_INVALID
   EndIf
   out_[512 - 1] = 0 'This statement forces a null termination in one did not exist
   Return out_
End Function
See http://msdn.microsoft.com/en-us/library ... S.85).aspx to reference the error code reported.
See http://msdn.microsoft.com/en-us/library ... S.85).aspx for details on RegQueryValueEx. You might notice a detail that I have not.
palahoot
Posts: 131
Joined: Dec 15, 2011 21:55

Re: How to get and display registry entries

Post by palahoot »

well that new piece of code (thanks codefoil) seems to have returned the following values:
234, followed by
2048 and then
reg_Key_invalid

and i can verify the type and value of the regkey by running regedit, amongst other programs... the key is valid and the type is reg_sz.

so based on the code that you added, then the return value of regqueryvalueex is 234 and the buffer is 2048, yes? so the first value is the error code (see below), but the second value is twice the size of the buffer. so i changed this line: Dim out_ As ZString * 2048 but i still have the same error.

what changes do i have to make to get this to not error out?

edit: i did check the links you suggested, is this the correct error output?
ERROR_MORE_DATA
234 (0xEA) More data is available

If the lpData buffer is too small to receive the data, the function returns ERROR_MORE_DATA.
codeFoil
Posts: 256
Joined: Dec 22, 2011 4:45
Location: United States
Contact:

Re: How to get and display registry entries

Post by codeFoil »

palahoot wrote:well that new piece of code (thanks codefoil) seems to have returned the following values:
234, followed by
2048 and then
reg_Key_invalid

and i can verify the type and value of the regkey by running regedit, amongst other programs... the key is valid and the type is reg_sz.

so based on the code that you added, then the return value of regqueryvalueex is 234 and the buffer is 2048, yes? so the first value is the error code (see below), but the second value is twice the size of the buffer. so i changed this line: Dim out_ As ZString * 2048 but i still have the same error.

what changes do i have to make to get this to not error out?

edit: i did check the links you suggested, is this the correct error output?
ERROR_MORE_DATA
234 (0xEA) More data is available

If the lpData buffer is too small to receive the data, the function returns ERROR_MORE_DATA.
You almost nailed it. You've allocated a buffer large enough, but the RegQueryValueEx routine has no way of determining this. The last parameter specifies the largest count of bytes you are prepared to receive. When that value is less than the size of the registry value data, RegQueryValueEx returns ERROR_MORE_DATA. You need to initialize the variable l (terrible variable name) to a large enough value. You also need to change the statement just before the function return so that it does not truncate the data returned.

However, unless you know the maximum size of the data that is going to be stored in your registry key value, I don't advise using this code. It was a good example, but it is not structured for general purpose use. The example code on the MSDN page for ReqQueryValueEx illustrates a different method. (also not ideal, but more flexible)

If you have a lot of time invested in your shelling technique, I wouldn't get bogged down right now with learning the API calls. If you do have the time, go for it.

By the way, the buffer size that is being requested might not necessarily be the size of the data in your registry value. It seems like quite a coincidence that the value that came back is exactly 2 kilobytes. This may simply be the minimum size that the API routine is willing to work with in this case. On the other hand, 2 kilobytes is the largest byte count that the SDK documentation recommends storing in a registry key value. Above that limit, it is recommended that the data be stored in a file, and a file name stored in the registry.
palahoot
Posts: 131
Joined: Dec 15, 2011 21:55

Re: How to get and display registry entries

Post by palahoot »

so should i change all of the dim l as dword =2048 then? and should it still be a dword? and what to change in the function so that it doesn't truncate?

yes the max size is 8096 according to the spec's for SET, but i cant image a "path" that is longer that 2048 characters so i think that i can safely set the max size to 2k.

no on the too much time in shelling, just unsure of the "best" way to implement. i can already save to disk, so that part is not an issue. just is it best to save it to: 1) registry? 2) file? 3) environment table. i like the envvar cause you can do "dir %return1%" or any other command that looks at directories or files (like copy filename.ext %return2% ).

so it depends on whether its best to use file vs registry or use all three to their best practice.

thoughts?
Post Reply