The Registry - Now I've got it what can I do?

Tuesday Nov 19th 2002 by John Percival
Share:

The Registry - Now I've got it what can I do?

So far in this series we have investigated the built in Registry functions in Visual Basic, as well as investigating most of the API functions that allow you complete access to all parts of the Registry.

In this article, I will show you how to get all the sub keys under a key (enumeration), as well as investigating the practical uses of the Registry, such as saving settings and changing the computer security settings.  I recommend that you read the previous article in this series in order to fully understand how the Registry is structured, as well as how the Windows API functions can be used.

As ever, I warn you to be careful with changing the registry, as it can have disastrous effects on the system. Make sure that you back up system.dat and user.dat in the windows directory before you do too much more.

Public Function GetAllKeys( _
   hKey As Long, _
   strPath As String) As Variant
Dim lRegResult As Long
Dim lCounter As Long
Dim hCurKey As Long
Dim strBuffer As String
Dim lDataBufferSize As Long
Dim strNames() As String
Dim intZeroPos As Integer
lCounter = 0
lRegResult = RegOpenKey(hKey, strPath, hCurKey)

Do
'initialise buffers (longest possible length=255)
lDataBufferSize = 255
strBuffer = String(lDataBufferSize, " ")
lRegResult = RegEnumKey(hCurKey, _
lCounter, strBuffer, lDataBufferSize)

If lRegResult = ERROR_SUCCESS Then

'tidy up string and save it
ReDim Preserve strNames(lCounter) As String

intZeroPos = InStr(strBuffer, Chr$(0))
If intZeroPos > 0 Then
strNames(UBound(strNames)) = Left$(strBuffer, intZeroPos - 1)
Else
strNames(UBound(strNames)) = strBuffer
End If

lCounter = lCounter + 1
Else
Exit Do
End If
Loop
GetAllKeys = strNames
End Function

This function works using the RegEnumKey function. You pass a number to the function and it returns the name of the sub key holding that position. These are numbered from 0, starting with the oldest, so you can get some idea of the age of keys using this API call. It initialises the buffer, and then makes the call. If the call returns ERROR_SUCCESS, there was a key at that number, but if it returns something else, there was either a problem, or all the keys have been retrieved.  It adds the retrieved name to an array, and continues. If there was an error, it exits the loop, otherwise it just keeps going.
The function returns an array of names in a variant. You would use it as follows:

Dim SubKeys As Variant
Dim KeyLoop As Integer
SubKeys = GetAllKeys(HKEY_CURRENT_USER, vbNullString)

If VarType(SubKeys) = vbArray + vbString Then
For KeyLoop = 0 To UBound(SubKeys)
Debug.Print SubKeys(KeyLoop)
Next
End If
Public Function GetAllValues( _
  hKey As Long, _
  strPath As String) As Variant
' Returns: a 2D array.
' (x,0) is value name
' (x,1) is value type (see constants)

Dim lRegResult As Long
Dim hCurKey As Long
Dim lValueNameSize As Long
Dim strValueName As String
Dim lCounter As Long
Dim byDataBuffer(4000) As Byte
Dim lDataBufferSize As Long
Dim lValueType As Long
Dim strNames() As String
Dim lTypes() As Long
Dim intZeroPos As Integer

lRegResult = RegOpenKey(hKey, _
               strPath, hCurKey)

Do
' Initialise bufffers
lValueNameSize = 255
strValueName = String$(lValueNameSize, " ")
lDataBufferSize = 4000

lRegResult = RegEnumValue(hCurKey, lCounter, _
strValueName, lValueNameSize, 0&, lValueType, _
byDataBuffer(0), lDataBufferSize)

If lRegResult = ERROR_SUCCESS Then

' Save the type
ReDim Preserve strNames(lCounter) As String
ReDim Preserve lTypes(lCounter) As Long
lTypes(UBound(lTypes)) = lValueType

'Tidy up string and save it
intZeroPos = InStr(strValueName, Chr$(0))
If intZeroPos > 0 Then
strNames(UBound(strNames)) = _
Left$(strValueName, intZeroPos - 1)
Else
strNames(UBound(strNames)) = strValueName
End If

lCounter = lCounter + 1

Else
Exit Do
End If
Loop

'Move data into array
Dim Finisheddata() As Variant
ReDim Finisheddata(UBound(strNames), 0 To 1) As Variant

For lCounter = 0 To UBound(strNames)
Finisheddata(lCounter, 0) = strNames(lCounter)
Finisheddata(lCounter, 1) = lTypes(lCounter)
Next

GetAllValues = Finisheddata

End Function

This function is slightly more complicated because we must know what type of data the value refers to. Because of this, this function returns a two dimensional array. The index for the value is the first dimension, and the second dimension is either 0 or 1. In 0, the name of the value is stored, and in 1, the type of data is stored. I decided to return the data type rather than the data because it makes the function easier, and also means that you can retrieve only the ones that you want, rather than eating up memory by retrieving then all.

In all other respects, this function is similar to the other. It has a counter, which counts from 0, retrieving the value names and data. The buffer length is set to 4000 because this is the largest binary type value. However, if you know that your largest value will be less than this, you can reduce it to lower the memory requirements.

Once all the data has been retrieved from the registry, it is moved into the array, which is passed from the function. This could not be done as we were going along because only the last dimension of a dynamic array can be resized. Since I wanted to keep in sync with the VB function, this seems to be the best way to do it.

Use the function in a similar way to the VB function. Although the line for printing the first element of the binary key looks slightly wrong, it is correct. Since the function returns an array, I access it outside the brackets of the function's parameters.

Dim Values As Variant
Dim KeyLoop As Integer
Dim RegPath As String
Dim HKCU As Long

HKCU = HKEY_CURRENT_USER ' to save typing
RegPath = "Software\Microsoft\Windows\CurrentVersion\Explorer"

Values = GetAllValues(HKCU, RegPath)

If VarType(Values) = vbArray + vbVariant Then

For KeyLoop = 0 To UBound(Values)
Debug.Print Values(KeyLoop, 0)

Select Case Values(KeyLoop, 1)
Case REG_DWORD
Debug.Print GetSettingLong(HKCU, RegPath, _
CStr(Values(KeyLoop, 0)))
Case REG_BINARY
Debug.Print GetSettingByte(HKCU, RegPath, _
Hex$(Values(KeyLoop, 0)))(0)
Case REG_SZ
Debug.Print GetSettingString(HKCU, RegPath, _
CStr(Values(KeyLoop, 0)))
End Select

Next

End If
Public Sub SaveFormPos( _
      frmSave As Form)
Dim strRegPath As String
strRegPath = "Software\" & App.CompanyName _
& "\" & App.Title & "\" & frmSave.Name

If frmSave.WindowState = vbMaximized Then
SaveSettingLong HKEY_CURRENT_USER, strRegPath, "Maximised", 1
DeleteValue HKEY_CURRENT_USER, strRegPath, "Left"
DeleteValue HKEY_CURRENT_USER, strRegPath, "Top"
DeleteValue HKEY_CURRENT_USER, strRegPath, "Width"
DeleteValue HKEY_CURRENT_USER, strRegPath, "Height"
Else
With frmSave
SaveSettingLong HKEY_CURRENT_USER, strRegPath, "Maximised", 0
SaveSettingLong HKEY_CURRENT_USER, strRegPath, "Left", .Left
SaveSettingLong HKEY_CURRENT_USER, strRegPath, "Top", .Top
SaveSettingLong HKEY_CURRENT_USER, strRegPath, "Width", .Width
SaveSettingLong HKEY_CURRENT_USER, strRegPath, "Height", .Height
End With
End If

End Sub

Public Sub LoadFormPos(frmLoad As Form)
Dim strRegPath As String
Dim IsMax As Long
strRegPath = "Software\" & App.CompanyName _
& "\" & App.Title & "\" & frmLoad.Name
IsMax = GetSettingLong(HKEY_CURRENT_USER, strRegPath, "Maximised", 2)

Select Case IsMax
Case 0
With frmLoad
.Move GetSettingLong(HKEY_CURRENT_USER, strRegPath, "Left", .Left), _
GetSettingLong(HKEY_CURRENT_USER, strRegPath, "Top", .Top), _
GetSettingLong(HKEY_CURRENT_USER, strRegPath, "Width", .Width), _
GetSettingLong(HKEY_CURRENT_USER, strRegPath, "Height", .Height)
End With

Case 1
frmLoad.WindowState = vbMaximized

Case 2
MsgBox "There is no form data saved for this form"

End Select

End Sub

This useful pair of functions allow you to save the position of the form in the registry, and load it at a later time. This is good when you have a small form that the user can move around, and will expect it in the same place next time they start. How it works is pretty self-explanatory. It uses the functions that I wrote last week in a module. The path that the information is saved to is HKEY_CURRENT_USER\CompanyName\AppName\FormName, so don't forget to set up the company name in Project Options.  It pops up a message box if there is no data saved, and you may want to catch this error, and set up a default position.

This idea is mainly applicable to Windows 95, although most work in Windows 98. I have not tried it under NT, but I doubt that it will work. They require a setting being set in the registry, and then some take immediate effect, while some require a restart of Windows to take full effect.

Most of this can be done with the product poledit.exe, available on the internet, but it has a very bad UI, and why not do it in your own applications anyway. The properties that I can set are called policies, and are found in HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies...

The four sub keys are Explorer, WinOldApp, Network and System.

i) Explorer

Disable Run Menu: "NoRun" - Prevents users running programs from the run command on the Start Menu. If you restart the computer, the menu item will be invisible.

Disable Find Menu: "NoFind" - Prevents users from searching the computer for files by disabling the find command.

Remove Shutdown Command: "NoClose" - This disables the Shut Down computer command. This prevents users Restarting windows, Shutting Down windows or exiting to DOS.

Don't save Settings: "NoSaveSettings" - This stops Windows saving the settings when you shut down. If this option is off, all the Explorer Windows that Ire open on shut down will reappear when you have restarted.

Hide all Items on the Desktop: "NoDesktop" - This option hides all the shortcuts on the desktop. You must restart your computer for this to take effect.

Disable Details and General Pages: "NoPrinterTabs" - This stops Windows showing the Details and General tabs in the properties of printers. On these tabs, you can change which ports you print to, which driver you use, and several other sensitive settings. Using this prevents users from tampering with these settings.

ii) System

Disable Display System Control Panel: "NoDispCPL" - This prevents the user calling up the Display Control Panel page, preventing them from changing the wallpaper, screensavers, colours and display settings.

Disable Configuration Page: "NoConfigPage" - This disables the hardware profiles tab on the System Control Panel, preventing the user from adding or removing system configurations.

Disable Device Manager Page: "NoDevMgrPage" -  This disables the Device Manager tab on the System Control Panel. This prevents users from adding, removing, or tampering with devices installed on the system.

Disable File System Page: "NoFileSysPage" - This disables the File System button on the performance tab on the System Control Panel. This stops users changing caching and troubleshooting settings. The troubleshooting settings reduce Windows' performance, if some of the features are not compatible.

Disable Virtual Memory Page: "NoVirtMemPage" - This disables the Virtual Memory button on the performance tab on the system control panel. This prevents users tampering with virtual memory settings. Virtual memory is a file on the hard disk, which is being used to complement the system RAM.

Disable Remote Administration Page: "NoAdminPage" -  Disables the Remote Administration tab on the Password Control Panel.

Disable User Profiles Page: "NoProfilePage" - Disables the User Profiles tab on the Password Control Panel. On this tab, you set whether all users use the same settings, or different ones.

Disable Change Passwords Page: "NoPwdPage" - This disables the Change Passwords tab on the Password Control Panel. This prevents users from changing their passwords.

Disable Password Control Panel: "NoSecCPL" - This disables the Password Control Panel page, preventing users from altering any of the above settings.

iii) WinOldApp

Disable MS-DOS prompt: "Disabled" - This prevents the computer running any MS-DOS based programs. The user cannot load the DOS prompt or any other program running in DOS. If there are any DOS programs running when this option is applied, they will not be affected.

iv) Network

Disable Network Control Panel: "NoNetSetup" - This prevents users from changing the settings to do with the network. These include, the network components, file/print sharing, and identification to other computers.

Disable Identification Page: "NoNetSetupIDPage" - This disables the Identification tab on the Network Control Panel, where you can change the computer name and workgroup name.

Disable Access Control Page: "NoNetSetupSecurityPage" - This disables the Access Control tab on the Network Control Panel page. This is where you can set who has what access to the shared resources on you computer.

Disable File and Print Sharing Controls: "NoFileSharingControl" - This removes the File and Print sharing button on the Configuration tab of the Network Control Panel. This button gives you control over whether users can access you files and printers.

Disable Password Caching: "DisablePwdCaching" - This stops the computer from storing Dial-Up Networking Passwords in a cache on the computer. Caching speeds up Windows, but is also a possible security risk.

I recommend that you set the value to 1 (long) if you want to enable it, and delete the value if you want to disable it. We have already written an application, which encompasses all of these features, and is available for download at http://www.jelsoft.com. It is called Stop'Em, and is a quick solution to preventing tampering.

So, to disable MS-DOS prompt, use:

SaveSettingLong HKEY_CURRENT_USER, "Software\Microsoft\Windows\CurrentVersion\Policies\WinOldApp", "Disabled", 1

And to re-enable:
DeleteValue HKEY_CURRENT_USER, "Software\Microsoft\Windows\CurrentVersion\Policies\WinOldApp", "Disabled"

Be particularly careful with playing with these settings, because in some cases, you may be able to lock yourself out of the computer altogether.

Have a look around the Internet for other tips and things that you can do with the registry. One of the best places that I found is http://www.regedit.com. This site includes things that you can do with windows (not necessarily programming based), and is a very good resource.

Share:
Home
Mobile Site | Full Site
Copyright 2017 © QuinStreet Inc. All Rights Reserved