Link to home
Start Free TrialLog in
Avatar of GustavoValdes
GustavoValdes

asked on

Unable to write to registry

Helo, I have a program that successfully writes to the HKEY_CURRENT_USER hive, especifically to the /SOFTWARE/ODBC/ODBC.INI key, however this works well in Windows98, when we migrate to Windows 2000 the program begins to raise errors. I realized that in Windows 2000 this values were under another hive HKEY_LOCAL_MACHINE, the key remains the same.
However when I try to overwrite any value I get an error and it is not a trappable error is and unhandled error for vb too because the whole IDE hangs.

Let me know how I can over come this.
Avatar of AzraSound
AzraSound
Flag of United States of America image

To write to the HKLM hive on Win2k or WinNT I believe the logged in user will need Admin rights.
Avatar of GustavoValdes
GustavoValdes

ASKER

I've already belong to the Admins group, so, I must supose that I have this kind of rights.
Not necessarily.  I am always logged into my Win2K machine as administrator and there were certain registry entries that I could not edit.  Under Win2K there are two registry's.  Regedit, is used primarily for indexed searching.  Regedt32 is the registry in which you want to write to.  Also, when running the Regedt32.exe you can go to the specific key you are having problems with and then select permissions from the menu bar.  You will see that you only have read access.  Being the administrator, you can then grant yourself permission to edit the registry key.  Hope this helps.

JDC0724
Not sure if you know this but i'll share anyways, since your most likly using API commands to access the registry I found a problem when moving my code from 9x to NT.

In 9x you report to the API function the size of the buffer plus the null char, however in NT the size must be exact (do not include the null char).

I did right a module containing all my registry access code the determines if your on 9x or NT then adjusts the buffer size value accordingly.

Maybe this is your problem maybe not. Good Luck,
RH.
JDC0724

    There is only one registry on any windows 32-bit OS. However under the Windows NT Family, two registry editors have been shipped, regedit.exe and regedt32.exe, the only supported editor for editing the NT registry is regedt32.exe. the only reason regedit.exe is included is to support editing Windows 95/98 registries from a NT machine
This is a part of the code, the offending line is the last one:

    'Find out windows' version
    If InStr(1, FindOutOS, "2000") Then
        'Look for a different registry fields
         lRetVal = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\ODBC\ODBC.INI\ActDatabase", hKey)
    Else
         lRetVal = RegOpenKey(HKEY_CURRENT_USER, "Software\ODBC\ODBC.INI\ActDatabase", hKey)
    End If

    'Tratar de abrir la llave de los ODBCs
    If lRetVal = ERROR_SUCCESS Then
        'key could be open/created
        sBuffer = LCase(sValorNuevo)
       
        lRetVal = RegSetValueEx(hKey, "ServerName", 0&, REG_SZ, ByVal sBuffer, Len(sBuffer))

When the program tries to execute this last line, VB crashes.

Like i said before you must report the correct buffer size
when writing to the registry.

'try this
If Win9x Then            'If 95/98/ME
'Len should return size of buffer plus null char
  lRetVal = RegSetValueEx(hKey, "ServerName", 0&, REG_SZ, ByVal sBuffer, Len(sBuffer))
ElseIf WinNT Then        'If NT/2K/XP
'Len should return size of buffer minus null char
  lRetVal = RegSetValueEx(hKey, "ServerName", 0&, REG_SZ, ByVal sBuffer, Len(sBuffer) - 1)
End If

Good Luck,
RH.
MCummings, thanks that is interesting to know.  I wasn't all that familiar with the NT registry setup and that is where I read that NT and 2000pro primarily used regedit.reg for quick searching purposes.  I originally tried to remove virus files from my 2000 computer assuming to use regedit.exe.  However, it wouldn't let me remove any of the virus keys.  That is where I did the reading on 2000pro registry and how they have shipped with both.  Once I went into regedi32.exe I was still denied access to delete the virus files but it allowed me the option of giving myself write access since I was the administrator.  Once I changed my privledges I was able to delete all the virus keys from regedt32.reg without a problem.
GustavoValdez, RHuebner, now that I have seen the code, I think your first and foremost problem is in your RegOpenKey calls.  These are the old and deprecated calls.  When you use RegOpenKey is uses the default security mask.  Then you try to write to the registry using the "correct" version of "regSetValueEx" which you need to specify a security mask.  

You need to change your "RegOpenKey" to "RegOpenKeyEx" and I think you will be all set.  Let me know if this works.

Thanks,
JDC
Ok, I've changed the code to use know the RegOpenKeyEx function, however all VB crashed when trying to set the registry value.

Thanks in advace for any clue.

Public Function SetCurrentServer(sValorAnterior As String, sValorNuevo As String) As Boolean
    Dim hKey            As Long
    Dim iLong           As Long
    Dim sBuffer         As String
    Dim lRetVal         As Long
   
    sBuffer = GetCurrentServer
   
    If sValorAnterior <> sBuffer Then
        'Los datos de configuración han sido cambiados manualmente
        MsgBox "The ODBC parameters have been changed manually after the last update performed by this program." & vbCrLf & "The active server is " & sBuffer, vbOKOnly + vbInformation, "Warning!"
        'MsgBox "Los datos de configuración han sido modificados maualmente posteriormente al último cambio hecho por este programa." & vbCrLf & "El servidor actual es " & sBuffer, vbOKOnly + vbInformation, "Advertencia"
        SetCurrentServer = False
        Exit Function
    End If
   
   
    'Determinar la version de windows
    If InStr(1, FindOutOS, "2000") Then
        'Look for a different registry fields
         lRetVal = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\ODBC\ODBC.INI\ActDatabase", 0&, KEY_ALL_ACCESS, hKey)
    Else
         lRetVal = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\ODBC\ODBC.INI\ActDatabase", 0&, KEY_ALL_ACCESS, hKey)
    End If

    'Tratar de abrir la llave de los ODBCs
    If lRetVal = ERROR_SUCCESS Then
        'La llave fue abierta exitosamente
       
        'Fijar los distintos valores del server
       
        'Cambiando el servidor
        sBuffer = LCase(sValorNuevo)
       
        lRetVal = RegSetValueEx(hKey, "ServerName", 0&, REG_SZ, ByVal sBuffer, Len(sBuffer) - 1)
       
        If lRetVal <> ERROR_SUCCESS Then
            MsgBox "The new server parameter could not be updated."
            'MsgBox "El valor de Servidor no pudo ser actualizado"
        End If
       
        'Cambiar el servicio
        sBuffer = LCase(sValorNuevo) & "tcp"
       
        lRetVal = RegSetValueEx(hKey, "Service", 0&, REG_SZ, ByVal sBuffer, Len(sBuffer))
       
        If lRetVal <> ERROR_SUCCESS Then
            MsgBox "The service parameter could not be updated."
            'MsgBox "El valor de Service no pudo ser actualizado"
        End If
       
        'Cambiar el Host Name
        sBuffer = LCase(sValorNuevo)
       
        lRetVal = RegSetValueEx(hKey, "HostName", 0&, REG_SZ, ByVal sBuffer, Len(sBuffer))
       
        If lRetVal <> ERROR_SUCCESS Then
            MsgBox "The hostname parameter could not be updated."
            MsgBox "El valor de HostName no pudo ser actualizado"
        End If
       
    Else
        'La llave no pudo hacer abierta exitosamente
        MsgBox "The ActDatabase DSN has not been defined."
        'MsgBox "No se ha definido el DSN ActDatabase."
        Exit Function
    End If

End Function
once again on setting the value of the registry key you must specify the size depending on the OS.

Add this or something like it..

'GET VERSION OF OPERATING SYSTEM
  Private Declare Function GetVersion& Lib "Kernel32" Alias "GetVersionExA" _
    (ByRef lpVersionInfo As OSVERSIONINFO)

  Private Type OSVERSIONINFO      'typedef struct _OSVERSIONINFO{
    dwOSVersionInfoSize As Long   '  DWORD dwOSVersionInfoSize &
    dwMajorVersion As Long        '  DWORD dwMajorVersion &
    dwMinorVersion As Long        '  DWORD dwMinorVersion &
    dwBuildNumber As Long         '  DWORD dwBuildNumber &
    dwPlatformId As Long          '  DWORD dwPlatformId &   is VER_PLATFORM
    szCSDVersion As String * 128  '  TCHAR szCSDVersion[ 128 ] &
  End Type                        '} OSVERSIONINFO &
Const VER_PLATFORM_WIN32s& = 0              'Windows 3.1 w/32 bit
Const VER_PLATFORM_WIN32_WINDOWS& = 1       'Windows 95,98,ME
Const VER_PLATFORM_WIN32_NT& = 2            'Windows NT,2K, XP?

'CONVERT AND RETURN ANSI LENGTH OF VB STRING
Private Function AnsiSize&(Expression As String)
  If WinVersion = "NT" Then 'SIZES ARE EXACT
    AnsiSize = LenB(StrConv(Expression, vbFromUnicode)) '+ 1
  Else                      'SIZE INCLUDES NULL CHAR
    AnsiSize = LenB(StrConv(Expression, vbFromUnicode)) + 1
  End If
End Function

Private Function WinVersion$()
Dim OS_INFO As OSVERSIONINFO, lRet&
  OS_INFO.dwOSVersionInfoSize = Len(OS_INFO) 'SET SIZE OF STRUCT
  lRet = GetVersion(OS_INFO)                          'GET OS VERSION INFO
  Select Case OS_INFO.dwPlatformId
   Case VER_PLATFORM_WIN32_NT: WinVersion = "NT"
   Case VER_PLATFORM_WIN32_WINDOWS:  WinVersion = "9x"
   Case VER_PLATFORM_WIN32_WINDOWS: WinVersion = "3x"
   'Else: Err.Raise "", "API", "UnRecognized Operating System"
  End Select
End Function

Then modify your calls from this...
lRetVal = RegSetValueEx(hKey, "HostName", 0&, REG_SZ, ByVal sBuffer, Len(sBuffer))

to this..
lRetVal = RegSetValueEx(hKey, "HostName", 0&, REG_SZ, ByVal sBuffer, AnsiSize(sBuffer))

weather you use the "Ex"  versioning of the call or not you still must specify the correct size.

RH.
Yes, that is correct.  The Buffer size still needs to correctly specified.  It seems there were a couple of issues here.
I have just added your function to determine the correct size of the string to be written in the registry and the error is the same.
This is the error.

The instruction at "0x77db9504" referenced memory at "0x00301d1f". The memory could not be "read".
ASKER CERTIFIED SOLUTION
Avatar of AzraSound
AzraSound
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks to everyone for your help.
In this case, AzraSound answer leads me to a sample project that shows me that there are more Registry Related API functions, especifically they are:
RegSetValueExStr
RegSetValueExLong
RegSetValueExByte

one for every type of registry key value, and I have test using this functions with the length modifications that some of you suggested me before depending on the OS, ant they work.

Thanks a lot.
FYI:
For future grading, see the grading guidelines at the following link:

https://www.experts-exchange.com/jsp/cmtyQuestAnswer.jsp#3


Glad you found a working solution.