Click to See Complete Forum and Search --> : Writing to HKEY_LOCAL_MACHINE registry in NT/2K


bigfredb
October 17th, 2001, 12:12 PM
I have a couple of VB programs which maintain options in the Registry in (HKEY_Local_Machine/software). It has been running under Win9x but we are migrating to NT/2K in the near future.

If the client is not an administrator, is it possible to write values to the registry area listed above? (Examples??)

Is there a better way that will work for all users who login to the machine??

Please Help . . .

Cimperiali
October 18th, 2001, 02:24 AM
Here I tried and it was impossible unless having local admin rights.
I think your best shot is to change the registry target to hkey_current_user when in winnt...

(Happy if I learn a way to do it to Local_Machine)
;-)


Special thanks to Lothar "the Great" Haensler, Tom Archer, Chris Eastwood, TCartwright, Bruno Paris, Dr_Michael
and all the other wonderful people who made and make Codeguru a great place.
Come back soon, you Gurus.

The Rater

phunkydude
October 18th, 2001, 06:54 AM
If the settings you are trying to write to the registry are universal across all User Profiles on the machine, then I suggest you use the LOCAL_MACHINE Hive. If the settings are User Specific, resort to the CURRENT_USER hive.

I have had success in creating, opening, querying and writing keys and values to the LOCAL_MACHINE\Software hive. After much searching on the MSDN and not coming up with anything significant, except that you should resort to using the registry APIs with suffixe 'Ex' on WinNT (I guess that goes for 2K as well).

Most of this, a copy & paste job from a template I use, was taken from www.allapi.net.

Play around, be snappy, that deadline is looming large, hopefully it helps.

' Constants required for values in the keys
private Const REG_NONE as Long = 0 ' No value type
private Const REG_SZ as Long = 1 ' nul terminated string
private Const REG_EXPAND_SZ as Long = 2 ' nul terminated string w/enviornment var
private Const REG_BINARY as Long = 3 ' Free form binary
private Const REG_DWORD as Long = 4 ' 32-bit number
private Const REG_DWORD_LITTLE_ENDIAN as Long = 4 ' 32-bit number (same as REG_DWORD)
private Const REG_DWORD_BIG_ENDIAN as Long = 5 ' 32-bit number
private Const REG_LINK as Long = 6 ' Symbolic Link (unicode)
private Const REG_MULTI_SZ as Long = 7 ' Multiple Unicode strings
private Const REG_RESOURCE_LIST as Long = 8 ' Resource list in the resource map
private Const REG_FULL_RESOURCE_DESCRIPTOR as Long = 9 ' Resource list in the hardware description
private Const REG_RESOURCE_REQUIREMENTS_LIST as Long = 10

'Registry Specific Access Rights (Fully Described)
private Const SYNCHRONIZE = &H100000
private Const READ_CONTROL = &H20000
private Const STANDARD_RIGHTS_ALL = &H1F0000
private Const STANDARD_RIGHTS_READ = (READ_CONTROL)
private Const STANDARD_RIGHTS_WRITE = (READ_CONTROL)
private Const KEY_QUERY_VALUE = &H1
private Const KEY_SET_VALUE = &H2
private Const KEY_CREATE_LINK = &H20
private Const KEY_CREATE_SUB_KEY = &H4
private Const KEY_ENUMERATE_SUB_KEYS = &H8
private Const KEY_NOTIFY = &H10
private Const KEY_ALL_ACCESS = ((STANDARD_RIGHTS_ALL Or KEY_QUERY_VALUE Or KEY_SET_VALUE Or KEY_CREATE_SUB_KEY Or KEY_ENUMERATE_SUB_KEYS Or KEY_NOTIFY Or KEY_CREATE_LINK) And (Not SYNCHRONIZE))
private Const KEY_READ = ((STANDARD_RIGHTS_READ Or KEY_QUERY_VALUE Or KEY_ENUMERATE_SUB_KEYS Or KEY_NOTIFY) And (Not SYNCHRONIZE))
private Const KEY_WRITE = ((STANDARD_RIGHTS_WRITE Or KEY_SET_VALUE Or KEY_CREATE_SUB_KEY) And (Not SYNCHRONIZE))
private Const REG_CREATED_NEW_KEY = &H1 ' new Registry Key created
private Const REG_OPENED_EXISTING_KEY = &H2 ' Existing Key opened

' Constants required for key locations in the registry
public Const HKEY_CLASSES_ROOT as Long = &H80000000
public Const HKEY_CURRENT_USER as Long = &H80000001
public Const HKEY_LOCAL_MACHINE as Long = &H80000002
public Const HKEY_USERS as Long = &H80000003
public Const HKEY_PERFORMANCE_DATA as Long = &H80000004
public Const HKEY_CURRENT_CONFIG as Long = &H80000005
public Const HKEY_DYN_DATA as Long = &H80000006

' Constants required for return values (error code checking)
private Const ERROR_SUCCESS as Long = 0
private Const ERROR_ACCESS_DENIED as Long = 5
private Const ERROR_NO_MORE_ITEMS as Long = 259

' Open/Create constants
private Const REG_OPTION_NON_VOLATILE as Long = 0
private Const REG_OPTION_VOLATILE as Long = &H1

'Security Constants
Const TOKEN_QUERY as Long = &H8&
Const TOKEN_ADJUST_PRIVILEGES as Long = &H20&
private Const SE_PRIVILEGE_ENABLED = &H2

private Const ANYSIZE_ARRAY = 1

private Type LUID
LowPart as Long
HighPart as Long
End Type

private Type LUID_AND_ATTRIBUTES
pLuid as LUID
Attributes as Long
End Type

private Type TOKEN_PRIVILEGES
PrivilegeCount as Long
Privileges(ANYSIZE_ARRAY) as LUID_AND_ATTRIBUTES
End Type

private Type LARGE_INTEGER
LowPart as Long
HighPart as Long
End Type

'Declarations Required for Security
private Declare Function GetCurrentProcess Lib "kernel32" () as Long

private Declare Function OpenProcessToken Lib "advapi32.dll" _
(byval ProcessHandle as Long, byval DesiredAccess as Long, _
TokenHandle as Long) _
as Long

private Declare Function LookupPrivilegeValue Lib "advapi32.dll" _
Alias "LookupPrivilegeValueA" _
(byval lpSystemName as string, byval lpName as string, lpLuid as LUID) _
as Long

private Declare Function AdjustTokenPrivileges Lib "advapi32.dll" _
(byval TokenHandle as Long, byval DisableAllPrivileges as Long, _
NewState as TOKEN_PRIVILEGES, byval BufferLength as Long, _
PreviousState as TOKEN_PRIVILEGES, ReturnLength as Long) _
as Long

' Declarations required to access the Windows registry
private Declare Function apiRegCloseKey Lib "advapi32.dll" Alias "RegCloseKey" (byval lngRootKey as Long) as Long

private Declare Function apiRegCreateKeyEx Lib "advapi32.dll" Alias "RegCreateKeyExA" _
(byval hKey as Long, byval lpSubKey as string, byval Reserved as Long, _
byval lpClass as string, byval dwOptions as Long, byval samDesired as Long, _
lpSecurityAttributes as Long, phkResult as Long, _
lpdwDisposition as Long) _
as Long

private Declare Function apiRegDeleteKey Lib "advapi32.dll" Alias "RegDeleteKeyA" _
(byval lngRootKey as Long, byval lpSubKey as string) as Long

private Declare Function apiRegDeleteValue Lib "advapi32.dll" Alias "RegDeleteValueA" _
(byval lngRootKey as Long, byval lpValueName as string) as Long

private Declare Function apiRegOpenKeyEx Lib "advapi32.dll" Alias "RegOpenKeyExA" _
(byval hKey as Long, byval lpSubKey as string, byval ulOptions as Long, _
byval samDesired as Long, phkResult as Long) _
as Long

private Declare Function apiRegQueryValueEx Lib "advapi32.dll" Alias "RegQueryValueExA" _
(byval lngRootKey as Long, byval lpValueName as string, byval lpReserved as Long, _
lpType as Long, lpData as Any, lpcbData as Long) as Long

private Declare Function apiRegSetValueEx Lib "advapi32.dll" Alias "RegSetValueExA" _
(byval lngRootKey as Long, byval lpValueName as string, byval Reserved as Long, _
byval dwType as Long, lpData as Any, byval cbData as Long) as Long

'private Function SetPrivilege(byval Privilege as string, byval Enable as Boolean) as Boolean
''Written by DesmondVDS
''If you like this, you use
' Dim lTokenHandle as Long
' Dim tp_temp as TOKEN_PRIVILEGES
' Dim tp_prev as TOKEN_PRIVILEGES
' Dim luid_temp as LUID
' Dim lRetLen as Long
' Dim lRetVal as Long
'
' lRetVal = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES Or TOKEN_QUERY, lTokenHandle)
' If lRetVal = 0 then
' 'an error occurred
' Exit Function
' ElseIf Err.LastDllError <> 0 then
' 'an error occurred
' Exit Function
' End If
'
' lRetVal = LookupPrivilegeValue(0&, seName, luid_temp) 'Used to look up privilege's LUID.
' If lRetVal = 0 then
' 'an error occurred
' Exit Function
' End If
'
' If Not LookupPrivilegeValue(vbNullString, Privilege, luid_temp) then
' 'an error occured
' else
' tp_temp.PrivilegeCount = 1
' tp_temp.Privileges.pLuid = luid_temp
' If Enable then
' tp_temp.Privileges.Attributes = SE_PRIVILEGE_ENABLED
' else
' tp_temp.Privileges.Attributes = 0
' End If
' End If
'
' SetPrivilege = AdjustTokenPrivileges(TokenHandle, false, tp_temp, len(tp_temp), tp_prev, lRetLen) <> 0
'End Function
'
public Function regDelete_Sub_Key(byval strRegKey as string, byval strRegSubKey as string) as Boolean
' Description: Function for removing a sub key.
on error GoTo Function_Error
Dim lKeyHandle as Long

If regDoes_Key_Exist(strRegKey) then

' get the key handle
m_lngRetVal = apiRegOpenKeyEx(HKEY_LOCAL_MACHINE, strRegKey, 0, KEY_ALL_ACCESS, lKeyHandle)

' Delete the sub key. If it does not exist, then ignore it.
m_lngRetVal = apiRegDeleteValue(lKeyHandle, strRegSubKey)

' Always close the handle in the registry. We do not want to
' corrupt the registry.
m_lngRetVal = apiRegCloseKey(lKeyHandle)
End If

Function_Exit:
If m_lngRetVal = ERROR_SUCCESS then
regDelete_Sub_Key = true
else
regDelete_Sub_Key = false
End If

Exit Function

Function_Error:
resume Function_Exit
End Function

public Function regDoes_Key_Exist(byval strRegKey as string) as Long
' Description: Function to see if a key does exist
on error GoTo Function_Error
Dim lKeyHandle as Long

lKeyHandle = 0

m_lngRetVal = apiRegOpenKeyEx(HKEY_LOCAL_MACHINE, strRegKey, 0, KEY_ALL_ACCESS, lKeyHandle)

If lKeyHandle = 0 then
regDoes_Key_Exist = false
else
regDoes_Key_Exist = true
End If

m_lngRetVal = apiRegCloseKey(lKeyHandle)

Function_Exit:
Exit Function

Function_Error:
resume Function_Exit
End Function

public Function regQuery_Key(byval strRegKey as string, byval strRegSubKey as string, optional byval vDefault as Variant) as Variant
' Description: Function for querying a sub key value.
Dim intPosition as Integer
Dim lKeyHandle as Long
Dim lngDataType as Long
Dim lngBufferSize as Long
Dim lngBuffer as Long
Dim strBuffer as string

lKeyHandle = 0
lngBufferSize = 0

m_lngRetVal = apiRegOpenKeyEx(HKEY_LOCAL_MACHINE, strRegKey, 0, KEY_ALL_ACCESS, lKeyHandle)

If lKeyHandle = 0 then
If Not IsMissing(vDefault) then
regQuery_Key = vDefault
else
regQuery_Key = ""
End If
m_lngRetVal = apiRegCloseKey(lKeyHandle) ' always close the handle
Exit Function
End If

' Query the registry and determine the data type.
m_lngRetVal = apiRegQueryValueEx(lKeyHandle, strRegSubKey, 0&, _
lngDataType, byval 0&, lngBufferSize)

If lKeyHandle = 0 then
If Not IsMissing(vDefault) then
regQuery_Key = vDefault
else
regQuery_Key = ""
End If
m_lngRetVal = apiRegCloseKey(lKeyHandle) ' always close the handle
Exit Function
End If

Select Case lngDataType
Case REG_SZ: ' string data (most common)
' Preload the receiving buffer area
strBuffer = Space(lngBufferSize)

m_lngRetVal = apiRegQueryValueEx(lKeyHandle, strRegSubKey, 0&, 0&, _
byval strBuffer, lngBufferSize)

' If NOT a successful call then leave
If m_lngRetVal <> ERROR_SUCCESS then
regQuery_Key = ""
else
' Strip out the string data
intPosition = InStr(1, strBuffer, Chr(0)) ' look for the first null char
If intPosition > 0 then
' if we found one, then save everything up to that point
regQuery_Key = Left(strBuffer, intPosition - 1)
else
' did not find one. Save everything.
regQuery_Key = strBuffer
End If
End If

Case REG_DWORD: ' Numeric data (Integer)
m_lngRetVal = apiRegQueryValueEx(lKeyHandle, strRegSubKey, 0&, lngDataType, _
lngBuffer, 4&) ' 4& = 4-byte word (long integer)

' If NOT a successful call then leave
If m_lngRetVal <> ERROR_SUCCESS then
regQuery_Key = ""
else
' Save the captured data
regQuery_Key = lngBuffer
End If

Case else: ' unknown
regQuery_Key = ""
End Select

If regQuery_Key = "" then
If Not IsMissing(vDefault) then
regQuery_Key = vDefault
else
regQuery_Key = ""
End If
End If

m_lngRetVal = apiRegCloseKey(lKeyHandle)

End Function

public Function regCreate_Key_Value(byval strRegKey as string, byval strRegSubKey as string, varRegData as Variant) as Boolean
' Description: Function for saving string data.
on error GoTo Function_Error
Dim lKeyHandle as Long
Dim lngDataType as Long
Dim lngKeyValue as Long
Dim strKeyValue as string
Dim lSecurity as Long
Dim lRetVal as Long

' Determine the type of data to be updated
If IsNumeric(varRegData) then
lngDataType = REG_DWORD
else
lngDataType = REG_SZ
End If

' m_lngRetVal = apiRegCreateKeyEx(HKEY_LOCAL_MACHINE, strRegKey, 0&, vbNullString, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0&, lKeyHandle, lRetVal)
lSecurity = 0&
m_lngRetVal = apiRegCreateKeyEx(HKEY_LOCAL_MACHINE, strRegKey, 0&, "REG_SZ", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, lSecurity, lKeyHandle, lRetVal)
Select Case lngDataType
Case REG_SZ: ' string data
strKeyValue = Trim(varRegData) & Chr(0) ' null terminated
m_lngRetVal = apiRegSetValueEx(lKeyHandle, strRegSubKey, 0&, lngDataType, _
byval strKeyValue, len(strKeyValue))

Case REG_DWORD: ' numeric data
lngKeyValue = CLng(varRegData)
m_lngRetVal = apiRegSetValueEx(lKeyHandle, strRegSubKey, 0&, lngDataType, _
lngKeyValue, 4&) ' 4& = 4-byte word (long integer)

End Select

m_lngRetVal = apiRegCloseKey(lKeyHandle)

Function_Exit:
If m_lngRetVal <> ERROR_SUCCESS then
regCreate_Key_Value = false
else
regCreate_Key_Value = true
End If

Exit Function

Function_Error:
resume Function_Exit
End Function

public Function regCreate_A_Key(byval strRegKey as string) as Long
' Description: This function will create a new key under the Application's Key
on error GoTo Function_Error
Dim lKeyHandle as Long
Dim lRetVal as Long

m_lngRetVal = apiRegCreateKeyEx(HKEY_LOCAL_MACHINE, strRegKey, 0&, vbNullString, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0&, lKeyHandle, lRetVal)

m_lngRetVal = apiRegCloseKey(lKeyHandle)

Function_Exit:
If m_lngRetVal <> ERROR_SUCCESS then
regCreate_A_Key = false
else
regCreate_A_Key = true
End If

Exit Function

Function_Error:
resume Function_Exit
End Function

public Function regDelete_A_Key(byval strRegSubKey, byval strRegKeyName as string) as Boolean
on error GoTo Function_Error
Dim lKeyHandle as Long

regDelete_A_Key = false

If regDoes_Key_Exist(strRegSubKey) then

' get the key handle
m_lngRetVal = apiRegOpenKeyEx(HKEY_LOCAL_MACHINE, strRegSubKey, 0, KEY_ALL_ACCESS, lKeyHandle)

' Delete the key
m_lngRetVal = apiRegDeleteKey(lKeyHandle, strRegKeyName)

' If the value returned is equal zero then we have succeeded
If m_lngRetVal = 0 then regDelete_A_Key = true

' Always close the handle in the registry. We do not want to
' corrupt the registry.
m_lngRetVal = apiRegCloseKey(lKeyHandle)
End If

Function_Exit:
If m_lngRetVal <> ERROR_SUCCESS then
regDelete_A_Key = false
else
regDelete_A_Key = true
End If

Exit Function

Function_Error:
resume Function_Exit
End Function

dubem
November 14th, 2001, 09:57 AM
Well,
the code works only when the user have Administrator privileges. What if he doesn't??? Is there a way to write to HKEY_LOCAL_MACHINE from a user without Administrative privileges? if not, is there a way to give the user Administrative privileges? I need to write to HKEY_LOCAL_MACHINE whatever the user have or don't have administrator privileges. SOmeone know how?
thank you
Martin