Fog Creek Software
Discussion Board




GetEnvironmentVariable API Call Broken in WinXP?

I know, I know, this is not a tech support orum.  But there are so many sharp coders here, I figure this is worth a try.

I have inherited an application that uses the GetEnvironmentVariable API to identify a machine for purposes of authenticating that a certain application can be accessed from that machine.  For those unfamiliar, here's the code that makes this call:

***START***
Declare Function GetEnvironmentVariable Lib "kernel32" Alias "GetEnvironmentVariableA" (ByVal lpName As String, ByVal lpBuffer As String, ByVal nSize As Long) As Long


Private Function GetClientName() As String

Dim strBuffer As String
Dim iLenBuffer As Integer
Dim retval As Integer

On Error GoTo Err_GetClientName

    strBuffer = Space(255)
    iLenBuffer = 255

    retval = GetEnvironmentVariable("CLIENTNAME", strBuffer, iLenBuffer)
    If Len(Trim(strBuffer)) <> 0 Then
        strBuffer = Left(strBuffer, Len(Trim(strBuffer)) - 1)
    Else
        ' probably no client name
        strBuffer = ""
    End If
   
Exit_GetClientName:
    Exit Function

Err_GetClientName:
        MsgBox Err.Description, , "Error in Function modUtil.GetClientName"
        Resume Exit_GetClientName
    Resume 0    ' .FOR TROUBLESHOOTING
End Function
***END***

In Windows98, the following entry must be made in AutoExec.bat before making the API call:

"SET CLIENTNAME=FOOBAR"

When you make the API call, bam!  The string "FOOBAR" is returned.

On an XP machine, the code runs and bam!  An empty string is returned.

"OK," I think to myself. "XP doesn't really use AutoExec.bat, it uses AutoExec.NT.  I'll set the ClientName in that file instead!  But that doesn't work either.

I notice that on XP, every so often the call will return the string "Console".  Aha!  I said.  On XP this API call is looking in the registry, not in a .bat file.  SO I searched the registry for every place where the string "Console" existed, and one by one replaced them with "FOOBAR" and re-ran the code.  I still got nothing.

Ten I wet to Control Panel > System > Advanced > Environment Variables and added a system variable named CLIENTNAME with a value of FOOBAR.

That did not work either, and now I am out of ideas.

Is there anyone who owns the API to the degree that they can tell me where exactly GetEnvironmentVariable is looking to get the value it returns?  I am well and truly stumped.

Norrick
Friday, November 21, 2003

Did you reboot after adding the environment variable to the control panel?

Rob Warner
Friday, November 21, 2003

This particular section of code is incorrect, although I don't know if it's causing the specific issue that you are seeing:
retval = GetEnvironmentVariable("CLIENTNAME", strBuffer, iLenBuffer)
    If Len(Trim(strBuffer)) <> 0 Then
        strBuffer = Left(strBuffer, Len(Trim(strBuffer)) - 1)

The GetEnvironmentVariable method, like many API calls, returns 0 for an error, or a non-zero buffer length if it succeeds (note that the buffer length returned by the API may be larger than the length of the buffer passed in, meaning that the buffer is not large enough).

The code above should be similar to:
retval = GetEnvironmentVariable("CLIENTNAME", strBuffer, iLenBuffer)
    If retval <> 0 Then
        strBuffer = Left(strBuffer, retval)  ' NOTE: this may need to be "retval - 1" if the return value buffer length includes the trailing null terminator character
    Else
        ' no CLIENTNAME found, should also check LastDllError and see if it's equal to ERROR_ENVVAR_NOT_FOUND.

Philip Dickerson
Friday, November 21, 2003

If you really want the actual client machine name, you may want to use one of the API methods GetComputerName or GetComputerNameEx. This retrieves the NetBIOS name or DNS name of the computer, and does not depend on any environment variables.

Philip Dickerson
Friday, November 21, 2003

2 suggestions:

1) Return a value from the function by assigning a value to GetClientName:

GetClientName = strBuffer

2) Try to query a known environment variable such as "TEMP".

GuyIncognito
Friday, November 21, 2003

I agree with Dickerson, but the %CLIENTNAME% environment variable should return a similar value.  I'd tend to go with Dickerson's suggestion though because it is heavily documented whereas the list of valid Windows enviromental variables doesn't seem to be.

GuyIncognito
Friday, November 21, 2003

Oh, by the way, you do NOT need to reboot an NT class machine (NT, 2000, XP) just to set an environment variable, like you did under Win9x.

Chris Tavares
Friday, November 21, 2003

GetEnvironmentVariable gets its information from the environment variables :)

Did you restart the IDE after changing the environment variable?

(The IDE won't get the updated environment until you run it; your program runs as a child of the IDE, and children inherit the environment of their parent.)

Insert half smiley here.
Friday, November 21, 2003

Dickerson wins...IF his code will return the computer name of a machine accessgin the app via Remote Desktop Connection.

Since this is an inherited app and there was no documentation, I've talked to everyone who had a hand in the project - nobody knows why the original developer did it this way.  And the original developer is nowhere to be found.

Norrick
Friday, November 21, 2003

"1) Return a value from the function by assigning a value to GetClientName:

GetClientName = strBuffer"

The function does do that, but I accidentally clipped it out when I pasted it in here and tried to format it nicely.  My bad.

Norrick
Friday, November 21, 2003

Chris is right.  Don't reboot.  Microsoft finally got environment variables right in Windows 2000.  You don't even need to restart explorer anymore!!  Hip, Hip hooray! 

christopher baus (www.baus.net)
Friday, November 21, 2003

At a guess it was done that way in the first place to work in multiple environments, DOS, Novell networks, Lan Manager, etc, etc.

From, umm NT I think,  onwards environment variables became case sensitive, though some early shells capitalised them on input.  Is the casing the same?

The original environment was a pointer to a list of null terminated strings you had to navigate yourself (DOS programming was such fun), but the API call should abstract you away from that.

Simon Lucy
Sunday, November 23, 2003

Oh, I should read more carefully. 

Autoexec.nt only gets run at the beginning of a console session, its not run on startup.  If you want to set an environment string on startup then you need to jimmy a small app that's referenced in the Registry.

Or, if its a constant for that machine  then you can set the environment string using Control Panel/System.  This can be either for the whole machine or just the current user.

Simon Lucy
Sunday, November 23, 2003

"From, umm NT I think,  onwards environment variables became case sensitive..."

That's not true - environment variables in NT are not case sensitive. Most enviornment variables are stored in the registry, which is case-insensitive...if you try to create a new environment variable with a different case than an existing one, it simply overwrites the existing variable.

Mike Treit
Sunday, November 23, 2003

*  Recent Topics

*  Fog Creek Home