3

With the following code, I experience horrible runtime:

Option Explicit

Dim ShellEnvironment: Set ShellEnvironment=CreateObject ("WScript.Shell").Environment ("USER")
Dim Name: Name="MyVar"
Dim NewVal: NewVal="This is my value"

Services.StartTransaction "SetEnv"
ShellEnvironment (Name)=NewVal
Services.EndTransaction ("SetEnv")

Note that only the Services.* stuff is QTP-specific. The two statements generate the following run result entry, indicating the runtime for the environment variable assignment:

Transaction "SetEnv" ended with "Pass" status (Total Duration: 12.1970 sec). 

This is on a very fast machine. Of course it is an unacceptable long runtime.

According to Environment.SetEnvironmentVariable takes a long time to set a variable at User or Machine level, this is because all top-level windows are notified with a 1-second timeout. I am not sure if that is C#-specific or not. Well, it obviously is not. But I don´t see how I can control this notification/timeout process under VBScript.

So generally speaking, the question is:

How can I set a USER environment variable in VBScript without getting the horrible runtime?

Community
  • 1
  • 1
TheBlastOne
  • 4,291
  • 3
  • 38
  • 72
  • 1
    Same issue here: http://superuser.com/questions/565771/setting-user-environment-variables-is-very-slow where in this case there's a comment blaming Chrome. Can you get away with doing this asynchronously, or do you need to do operations that rely on the new variable immediately after setting it? – Xiaofu Jan 27 '14 at 16:00
  • I have zero experience with QTP, but my first step would be to determine which instruction is taking too long by echoing timestamps before/after each instruction. – Ansgar Wiechers Jan 27 '14 at 17:54
  • I could live with async flow of execution. But -- how would I do that in QTP/VBScript? – TheBlastOne Jan 27 '14 at 18:27
  • Ansgar, the statement eating all those 12 seconds is the `ShellEnvironment (Name)=NewVal` line. I think the problem is that, in contrast to the C# runtime stuff, the VBScript scripting host Environment API does not allow you to customize the timeout. It is not even documented. Or, maybe the culprit is even more low-level. I just hate to write my own setenv-by-registry-patching code just due to that stupid timeout. – TheBlastOne Jan 27 '14 at 18:27
  • OK so the current idea for a would be to re-implement the env access with registry manipulation and doing the broadcast there, with a shorter timeout (or non at all?). That´s quite some code to write, debug, and maintain. I´d love to avoid that...isn´t there some way to control the timeout that the ShellEnvironment API uses? Or is it really the classic case of having to change a small detail in the way things work with the API not supporting that detail...sigh...? – TheBlastOne Feb 03 '14 at 10:56
  • 1
    @TheBlastOne In my case the "culprit" seems to be Visual Studio Code. If I close it the speed is high. – Alessandro Jacopson May 15 '20 at 10:30

2 Answers2

1

This is a nice workaround (in C#):

var envName = "USERNAME";

var envValue = "JERRY";

// it's up to you if you await this or not
Task.Factory.StartNew(() => Environment.SetEnvironmentVariable(envName, envValue, EnvironmentVariableTarget.User));
Jerry Nixon
  • 31,313
  • 14
  • 117
  • 233
0

There seems to be no way to control the timeout that ShellEnvironment uses for the notification broadcast.

So I decided to build a workaround.

I call this script:

Option Explicit

Dim Name
Dim NewVal

If WScript.Arguments.Count <> 2 then
    WScript.Echo "setUSEREnv.vbs: Pass name and value of USER environment variable to set on the command line"
    WScript.Quit (1)
End If  

Name=CStr (WScript.Arguments.Item (0))
NewVal=CStr (WScript.Arguments.Item (1))

Dim ShellEnvironment: Set ShellEnvironment=CreateObject ("WScript.Shell").Environment ("USER")
If ShellEnvironment (Name) <> NewVal then
    ShellEnvironment (Name)=NewVal
    WScript.Echo "Setting USER env var '" & Name & "'..."
    WScript.Echo "USER env var '" & Name & "' set to '" & NewVal & "'"
else
    WScript.Echo "USER env var '" & Name & "' already is '" & NewVal & "'"  
End If

from my setenv function code using Run:

Dim ShellEnvironment: Set ShellEnvironment=CreateObject ("WScript.Shell").Environment ("USER")

Dim Name: Name=EnvVarName
If ShellEnvironment (Name) <> NewVal Then
    Dim Shell: Set Shell=CreateObject ("WScript.Shell")
    Shell.Run "cscript.exe ""c:\mydir\setUSERENV.vbs"" " & Name & " " & CStr (NewVal), 0, false
End If

This still insults me with a long delay for every env var write access, but at least the main script keeps running, and so I don´t have to wait.

TheBlastOne
  • 4,291
  • 3
  • 38
  • 72