Set Shell environment for cmd.exe?

Is it possible from an app to set the environment for the spawned cmd.exe so that customer paths and variables are known?

a) Make the shell mode 2 and send commands to set up the environment when you first create it.
b) Write out a shell script and have cmd.exe execute that. Put your setup in the script.

I was pretty sure, but hope springs eternal. I also learned the hard way that Shell.Backend = “myzsh.exe” doesn’t do good things, either :frowning: (feature request in on that, though…). Time for more refactoring to make an old OS X / Linux tool Windows-fide.

I am learning to despise Windows more and more each day. So much so that I’m thinking about licensing CygWin as part of our app to make the trifecta more of a “win” situation than a “when” situation so that the Unix goodness that I’m used to is easily duplicated.

On Windows you CAN run cmd.exe and that should set up the windows environment

For history and the forum archive - The problem there is that you lose the Completion event and also can’t depend on “IsRunning” by default. To fix this, you must remember to add an “exit” command to the end of your command sequence. Here’s an example that calls “ls” (part of my specialized Unix-y environment) and displays the result in a TextArea:

  Dim theShell As New Shell
  Dim thePathEnv As String
  theShell.Mode = 2
  theShell.TimeOut = -1
  
  theShell.Execute "cmd.exe /q"
  theShell.WriteLine "prompt $b" 
  theShell.WriteLine "echo START"
  theshell.WriteLine "ls -l C:\"
  theShell.WriteLine "echo FINISH"
  theShell.WriteLine "exit"
  Do
    App.DoEvents // don't judge
  Loop Until Not theShell.IsRunning
  TextArea1.SelText = NthField(NthField(theShell.ReadAll, "START", 2), "FINISH", 1)

The results will look something like this:



|total 813188
drwxrwxrwx   1 user     group           0 Mar 15 18:06 $Recycle.Bin
-rw-rw-rw-   1 user     group           1 Jun 18  2013 BOOTNXT
drwxrwxrwx   1 user     group           0 Aug 22  2013 Documents and Settings
dr-xr-xr-x   1 user     group           0 Mar 15 18:09 MSOCache
drwxrwxrwx   1 user     group           0 Mar 15 17:27 NVIDIA
drwxrwxrwx   1 user     group           0 Aug 22  2013 PerfLogs
dr-xr-xr-x   1 user     group           0 Mar 31 01:31 Program Files
dr-xr-xr-x   1 user     group           0 Apr  2 16:42 Program Files (x86)
drwxrwxrwx   1 user     group           0 Apr  2 18:08 ProgramData
drwxrwxrwx   1 user     group           0 Apr  2 07:02 System Volume Information
dr-xr-xr-x   1 user     group           0 Mar 15 18:04 Users
drwxrwxrwx   1 user     group           0 Apr  1 14:52 Windows
-r--r--r--   1 user     group      427680 Aug 21  2013 bootmgr
-rw-rw-rw-   1 user     group        5078 Mar 15 18:07 cpqsprt.trace
drwxrwxrwx   1 user     group           0 Mar 15 18:07 cpqsystem
-rw-rw-rw-   1 user     group    815493120 Apr  2 16:44 hiberfil.sys
-rw-rw-rw-   1 user     group           0 Apr  2 16:44 pagefile.sys
-rw-rw-rw-   1 user     group    16777216 Apr  2 16:44 swapfile.sys

|

Note that you could further strip the “|” symbols (from the “prompt $b” command). I also tried using “echo off” instead of setting the prompt, but sometimes I need to execute multiple commands and the “|” lets me separate the results.

Ah yes about the events that won’t fire as expected if you do run cmd.exe

And could you not just yield to next thread instead of do events ?

Hey - you judged :P. Actually, any type of yield works there. That was just from a helper console app that I use. I threw the TextArea into the code so others could see the effect of the prompt and nthfield operations.

No
Judging would be “OMG TIm really DO EVENTS ?” :stuck_out_tongue:

If all you need is any kind of yield then the loop boundary functions as one so you could just sleep the current thread :slight_smile:

:S
Except that the code was from a Console app where DoEvents is the best solution.

On windows there is another way to do this by use of OLEObject.

This example is using environment type: Process which is not stored in the registry.

  Dim wshShell As OLEObject
  Dim objEnv As OLEObject
  
  Dim envString as String
  Dim myShell As Shell
  
  wshShell = New OLEObject("WScript.Shell")
  objEnv = wshShell.Environment("Process")  // Using Environment type: Process Not stored in the registry
  
  envString = OBJenv.Item("PATH")
  msgbox("Before: "+EndOfLine+EndOfLine+envString)
  
  objEnv.Item("PATH")  = envString+"C:\\bin\\ProcessExplorer"  // Installed ProcessExplorer from Sysinternals
  
  envString = OBJenv.Item("PATH")
  msgbox("After: "+EndOfLine+EndOfLine+envString)
  
  
  myShell = New Shell
  myShell.execute("procexp.exe")  //  run ProcessExplorer

  wshShell = nil

exception err as oleexception 
   msgbox err.message

If you want to store your environment in users profile. You use environment Type: User

You only need to change this line from: objEnv = wshShell.Environment(“Process”) to: objEnv = wshShell.Environment(“User”)

You can find more information about this on: http://technet.microsoft.com/en-us/library/ee156595.aspx

You CAN set environment variables via System.EnvironmentVariable and those values will be set in the Shell process. I had forgotten that when I wrote my response back in November.

Thanks Tim :slight_smile:

I had forgotten that too.

LOL Xojo has too many features

Link is here: http://documentation.xojo.com/index.php/System.EnvironmentVariable