Reputation: 21
I have the following code to create a combo box that shows a list of ports in use on the PC What I want to do is take the users choice of port and assign it to a system variable using the SETX command. At the moment the user enters the port number manually in a batch file, the aim is to skip this step and replace it with the choice from the combo box
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
myPort = IO.Ports.SerialPort.GetPortNames()
ComboBox1.Items.AddRange(myPort)
The batch file looks like this at present and works fine
set /p port= "What is your port number "
setx port "%port%"
So is there a way to remove the user having to enter the port number and have the batch file run its script using the choice from the combo box Thanks
Upvotes: 0
Views: 173
Reputation: 21
Well after much hard work and back and forth I finally figured out how to achieve my goal, I would like to thank @User09938 for sticking with me and for offering all the advice, is was just down to me to interpret it as a VB newbie and make it work for me.
I followed this guide see what is attached to a com port and show in combo box
and added the statement
Environment.SetEnvironmentVariable("port", ComboBoxComPorts.SelectedValue.ToString(), EnvironmentVariableTarget.Process)
and
Environment.SetEnvironmentVariable("port", ComboBoxComPorts.SelectedValue.ToString(), EnvironmentVariableTarget.User)
Which worked.
To those who are adventuring into VB for the first time I have to say that this site is so very helpful
Upvotes: 0
Reputation: 4991
According to this post
set modifies the current shell's (the window's) environment values, and the change is available immediately, but it is temporary. The change will not affect other shells that are running, and as soon as you close the shell, the new value is lost until such time as you run set again.
setx modifies the value permanently, which affects all future shells, but does not modify the environment of the shells already running. You have to exit the shell and reopen it before the change will be available, but the value will remain modified until you change it again.
For set /p port= "What is your port number: "
one can use the following in VB.NET:
Environment.SetEnvironmentVariable("port", "COM5", EnvironmentVariableTarget.Process)
where "COM5" is your port number (replace this with the value from your ComboBox).
For setx port "%port%"
:
Permanent environment variables are stored in the registry: HKEY_CURRENT_USER\Environment
.
To set an environment variable in HKEY_CURRENT_USER\Environment
, do one of the following.
Option 1:
'by specifying 'EnvironmentVariableTarget.User', the value will be updated in the registry (HKEY_CURRENT_USER\Environment)
Environment.SetEnvironmentVariable("port", "COM5", EnvironmentVariableTarget.User)
where "COM5" is your port number (replace this with the value from your ComboBox).
Option 2:
Add Imports
SetUserEnvironmentVarReg:
Private Sub SetUserEnvironmentVarReg(name As String, val As String, Optional regView As RegistryView = RegistryView.Registry64)
Using currentUserKey As RegistryKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, regView)
Using envKey As RegistryKey = currentUserKey.OpenSubKey("Environment", True)
If envKey IsNot Nothing Then
'set value
envKey.SetValue(name, val)
End If
End Using
End Using
End Sub
Usage:
SetUserEnvironmentVarReg("port", "COM5")
where "COM5" is your port number (replace this with the value from your ComboBox).
Let's create a test batch script. The test batch script will allow one command-line argument which will allow it to be used with the different options shown below. If a command-line argument is supplied, the batch script will used the specified value, otherwise it will use the value inherited from the environment variable.
TestEnvVar.bat:
@echo off
if not "%1" equ "" (
set port=%1
)
echo port: %port%
One can use System.Diagnostics.Process to run the batch script.
RunProcessInheritEnvironmentVar:
Private Sub RunProcessInheritEnvironmentVar(filename As String, portName As String)
'set environment variable (process-level)
Environment.SetEnvironmentVariable("port", portName, EnvironmentVariableTarget.Process)
'set environment variable (user-level)
'sets environment variable in HKEY_CURRENT_USER\Environment
Environment.SetEnvironmentVariable("port", portName, EnvironmentVariableTarget.User)
Dim startInfo As ProcessStartInfo = New ProcessStartInfo(filename) With {.CreateNoWindow = True, .RedirectStandardError = True, .RedirectStandardOutput = True, .UseShellExecute = False, .WindowStyle = ProcessWindowStyle.Hidden}
Using p As Process = New Process() With {.EnableRaisingEvents = True, .StartInfo = startInfo}
AddHandler p.ErrorDataReceived, Sub(sender As Object, e As DataReceivedEventArgs)
If Not String.IsNullOrEmpty(e.Data) Then
'ToDo: add desired code
Debug.WriteLine("error: " & e.Data)
End If
End Sub
AddHandler p.OutputDataReceived, Sub(sender As Object, e As DataReceivedEventArgs)
If Not String.IsNullOrEmpty(e.Data) Then
'ToDo: add desired code
Debug.WriteLine("output: " & e.Data)
End If
End Sub
p.Start()
p.BeginErrorReadLine()
p.BeginOutputReadLine()
'wait for exit
p.WaitForExit()
End Using
End Sub
Usage:
RunProcessInheritEnvironmentVar("C:\Temp\TestEnvVar.bat", "COM5")
where "COM5" is your port number (replace this with the value from your ComboBox).
It's not clear whether or not you actually need to set the environment variable permanently (ie: in HKEY_CURRENT_USER\Environment). If the environment variable is only being used for the batch script being executed, one may consider one of the alternate methods shown below.
When using System.Diagnostics.Process an environment variable can be set using ProcessStartInfo.EnvironmentVariables which sets the environment variable within the scope of the System.Diagnostics.Process
process. The code below doesn't change the value in the registry.
RunProcessSetEnvironmentVar :
Private Sub RunProcessSetEnvironmentVar(filename As String, portName As String)
Dim startInfo As ProcessStartInfo = New ProcessStartInfo(filename) With {.CreateNoWindow = True, .RedirectStandardError = True, .RedirectStandardOutput = True, .UseShellExecute = False, .WindowStyle = ProcessWindowStyle.Hidden}
'add environment variable
startInfo.Environment.Add("port", portName)
Using p As Process = New Process() With {.EnableRaisingEvents = True, .StartInfo = startInfo}
AddHandler p.ErrorDataReceived, Sub(sender As Object, e As DataReceivedEventArgs)
If Not String.IsNullOrEmpty(e.Data) Then
'ToDo: add desired code
Debug.WriteLine("error: " & e.Data)
End If
End Sub
AddHandler p.OutputDataReceived, Sub(sender As Object, e As DataReceivedEventArgs)
If Not String.IsNullOrEmpty(e.Data) Then
'ToDo: add desired code
Debug.WriteLine("output: " & e.Data)
End If
End Sub
p.Start()
p.BeginErrorReadLine()
p.BeginOutputReadLine()
'wait for exit
p.WaitForExit()
End Using
End Sub
Usage:
RunProcessSetEnvironmentVar("C:\Temp\TestEnvVar.bat", "COM5")
where "COM5" is your port number (replace this with the value from your ComboBox).
Lastly, let's look at how one could specify the port name as an argument because the test batch script allows command-line arguments. The code below doesn't change the value in the registry.
RunProcessWithArgument:
Private Sub RunProcessWithArgument(filename As String, Optional arguments As String = Nothing)
Dim startInfo As ProcessStartInfo = New ProcessStartInfo(filename) With {.CreateNoWindow = True, .RedirectStandardError = True, .RedirectStandardOutput = True, .UseShellExecute = False, .WindowStyle = ProcessWindowStyle.Hidden}
If Not String.IsNullOrEmpty(arguments) Then
startInfo.Arguments = arguments
End If
Using p As Process = New Process() With {.EnableRaisingEvents = True, .StartInfo = startInfo}
AddHandler p.ErrorDataReceived, Sub(sender As Object, e As DataReceivedEventArgs)
If Not String.IsNullOrEmpty(e.Data) Then
'ToDo: add desired code
Debug.WriteLine("error: " & e.Data)
End If
End Sub
AddHandler p.OutputDataReceived, Sub(sender As Object, e As DataReceivedEventArgs)
If Not String.IsNullOrEmpty(e.Data) Then
'ToDo: add desired code
Debug.WriteLine("output: " & e.Data)
End If
End Sub
p.Start()
p.BeginErrorReadLine()
p.BeginOutputReadLine()
'wait for exit
p.WaitForExit()
End Using
End Sub
Usage
RunProcessWithArgument("C:\Temp\TestEnvVar.bat", "COM5")
where "COM5" is your port number (replace this with the value from your ComboBox).
I've shown a variety of methods that can be used to specify an environment variable that can be used for a batch script depending upon your needs. For a slight variation of System.Diagnostics.Process usage see here.
Update:
When using System.Diagnostics.Process, one can also use StandardInput to provide value(s) for prompt(s).
TestEnvVar.bat:
@echo off
set /p port= "What is your port number: "
setx port "%port%"
echo port: %port%
for /f "delims=" %%a in ('^(reg query "HKCU\Environment" /v "port" ^|find /i "port"^)') do (
echo %%a
)
RunProcessWithStandardInput:
Private Sub RunProcessWithStandardInput(filename As String, portName As String)
If String.IsNullOrEmpty(filename) Then
Throw New Exception("Error: 'filename' is null or empty.")
ElseIf Not System.IO.File.Exists(filename) Then
Throw New Exception($"Error: '{filename}' could not be found.")
End If
If String.IsNullOrEmpty(portName) Then
Throw New Exception("Error: 'portName' is null or empty.")
End If
Dim startInfo As ProcessStartInfo = New ProcessStartInfo(filename) With {.CreateNoWindow = True, .RedirectStandardError = True, .RedirectStandardInput = True, .RedirectStandardOutput = True, .UseShellExecute = False, .WindowStyle = ProcessWindowStyle.Hidden}
Using p As Process = New Process() With {.EnableRaisingEvents = True, .StartInfo = startInfo}
AddHandler p.ErrorDataReceived, Sub(sender As Object, e As DataReceivedEventArgs)
If Not String.IsNullOrEmpty(e.Data) Then
'ToDo: add desired code
Debug.WriteLine("error: " & e.Data)
End If
End Sub
AddHandler p.OutputDataReceived, Sub(sender As Object, e As DataReceivedEventArgs)
If Not String.IsNullOrEmpty(e.Data) Then
'ToDo: add desired code
Debug.WriteLine("output: " & e.Data)
End If
End Sub
p.Start()
p.BeginErrorReadLine()
p.BeginOutputReadLine()
Using sw As System.IO.StreamWriter = p.StandardInput
'provide values for each input prompt
'ToDo: add values for each input prompt - changing the for loop as necessary
'Note: Since we only have 1 prompt, using a loop Is unnecessary - a single 'WriteLine' statement would suffice
'if there are additional prompts add them below; else if (i = 1)...
For i As Integer = 0 To 1
If i = 0 Then
'write port name to StandardInput
sw.WriteLine(portName)
End If
Next
End Using
'wait for exit
p.WaitForExit()
End Using
End Sub
Usage:
RunProcessWithStandardInput("C:\Temp\TestEnvVar.bat", "COM5")
where "COM5" is your port number (replace this with the value from your ComboBox).
Additional Resources:
Upvotes: 1