Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / VB.NET / March 2008

Tip: Looking for answers? Try searching our database.

Environment Variables Go "Poof"

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Scott McNair - 06 Mar 2008 20:24 GMT
Hi,

I'm trying to set an environment variable programmatically.  I've added
these three lines to my code:

System.Environment.SetEnvironmentVariable("TCS", "C:\Program Files\TCS\")
InstallPath = System.Environment.GetEnvironmentVariable("TCS")
MsgBox(InstallPath)

And, as expected, the MsgBox contains "C:\Program Files\TCS\".

However the variable seems to exist only for that instance of the app.  For
example, if I open a cmd window while the app is running and type "echo %
TCS%", it just returns "%TCS%".  If I exit the app, remark out the first
line, and then re-run the app, the MsgBox returns an empty box.

I'm guessing that any environment variables you set using
System.Environment.SetEnvironmentVariable are volatile; that is, they don't
exist outside that currently running application.  

How can I set it programmatically, and have it STAY there?

Regards,
Scott
Tom Shelton - 06 Mar 2008 20:53 GMT
> Hi,
>
[quoted text clipped - 20 lines]
> Regards,
> Scott

Your correct, Environment variables created in this way are volatile -
they only last for the life time of the process and only for that
process.  If you want to make them system wide, then there are two
things you need to do...

1)  Add the variable to the
HKLM\System\CurrentControlSet\Control\Session Manager\Environment key in
the registry.  You can do this with the Microsoft.Win32.Registry class.

2) Send out a broadcast message to with SendMessage (your going to need
to use P/Invoke here) with a value of WM_SETTINGCHANGE (&H1A)  and the lParam
set to the string Environment

HTH

Signature

Tom Shelton

Scott McNair - 06 Mar 2008 21:09 GMT
Tom Shelton <tom_shelton@YOUKNOWTHEDRILLcomcast.net> wrote in news:#
$bWrw8fIHA.2000@TK2MSFTNGP03.phx.gbl:

> 1)  Add the variable to the
> HKLM\System\CurrentControlSet\Control\Session Manager\Environment key in
> the registry.  You can do this with the Microsoft.Win32.Registry class.

Thanks for your help.  I've added the key using the registry, and although
it shows up via regedit, I still can't access the key either
programmatically or thru the command prompt.  I'm assuming I need to log
off/on to reload these variables?

Also I have a secondary question about volatile environment variables.  
Let's say I have an application, Foo.exe, that sets a volatile environment
variable and then calls Bar.exe.  Does Bar have access to the key set with
Foo since it was spawned by Foo, or does the variable exist only within the
scope of Foo itself?
Tom Shelton - 06 Mar 2008 21:19 GMT
> Tom Shelton <tom_shelton@YOUKNOWTHEDRILLcomcast.net> wrote in news:#
> $bWrw8fIHA.2000@TK2MSFTNGP03.phx.gbl:
[quoted text clipped - 7 lines]
> programmatically or thru the command prompt.  I'm assuming I need to log
> off/on to reload these variables?

Did you broadcast the wm_settingchange message (call to SendMessage with
a hwnd of -1)?

> Also I have a secondary question about volatile environment variables.  
> Let's say I have an application, Foo.exe, that sets a volatile environment
> variable and then calls Bar.exe.  Does Bar have access to the key set with
> Foo since it was spawned by Foo, or does the variable exist only within the
> scope of Foo itself?

Hmmm...  I can't remember for sure if they are inherited by spawned
processes.  I know it's possible to cause a spawned process to inherit
some things via a call to createprocess - but, I don't think you need to
do that :)

The way I would approach that is to add the varialbe (if it doesn't
already exist) to the Process.StartInfo.EnvironmentVariables collection.

Signature

Tom Shelton

Scott McNair - 06 Mar 2008 21:25 GMT
Tom Shelton <tom_shelton@YOUKNOWTHEDRILLcomcast.net> wrote in news:OuI38#
8fIHA.5348@TK2MSFTNGP03.phx.gbl:

> Did you broadcast the wm_settingchange message (call to SendMessage with
> a hwnd of -1)?

Ah, I had misunderstood your prior post... I was thinking you were giving a
choice of two things to try, rather than a list of things to do, in order.

I'm trying to find some documentation for P/Invoke for VB.NET, but I'm not
having much luck.  Could you provide a sample line of code (or a link) to
point me in the right direction?

Regards,
Scott
Tom Shelton - 06 Mar 2008 21:35 GMT
> Tom Shelton <tom_shelton@YOUKNOWTHEDRILLcomcast.net> wrote in news:OuI38#
> 8fIHA.5348@TK2MSFTNGP03.phx.gbl:
[quoted text clipped - 11 lines]
> Regards,
> Scott

Sure...  Off the top of my head :)

Private Const WM_SETTINGCHANGE As Integer = &H1A
Private Shared ReadOnly HWND_BROADCAST As New IntPtr (-1)

Private Declare Auto Function SendMessage Lib "User32" ( _
    ByVal hWnd As IntPtr, _
    ByVal Msg As Integer, _
    ByVal wParam As IntPtr, _
    ByVal lParam As String) As Integer

SendMessage (HWND_BROADCAST, WM_SETTINGCHANGE, IntPtr.Zero,
"Environment")

Anyway, that should be pretty close.   If you have any issues let me
know and I'll actually look up SendMessage and test some code :)

Signature

Tom Shelton

Scott McNair - 06 Mar 2008 21:45 GMT
> If you have any issues let me know and I'll actually look up
> SendMessage and test some code :)

Thanks, Tom.

I entered your code, and it seems to hang when I use SendMessage.
Tom Shelton - 06 Mar 2008 22:11 GMT
>> If you have any issues let me know and I'll actually look up
>> SendMessage and test some code :)
>
> Thanks, Tom.
>
> I entered your code, and it seems to hang when I use SendMessage.

I tested it here just now - and it is working.  The call can take
a few moments, because it has to notify all the top level windows on the
system - and SendMessage will wait for all to return...

Are us sure it is hanging permanetly?
Signature

Tom Shelton

Scott McNair - 06 Mar 2008 22:31 GMT
> Are us sure it is hanging permanetly?

Hi Tom,

Just to make sure, I started the app and let it sit there, to see how long
it would take (if ever) to execute.  So far it's been sitting for about ten
minutes.

I use the term "hung up" loosely... it's not technically hung; it's almost
as if it's waiting for some input from some source that I can't see.

I put the following lines of code into my Form_Load:

   Microsoft.Win32.Registry.SetValue( _
      "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\" & _
      "Session Manager\Environment\", "TCS", "C:\Program Files\TCS\")
   Dim StartTime As DateTime = Now()
   SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, IntPtr.Zero, _
      "Environment")
   MsgBox(DateDiff(DateInterval.Second, StartTime, Now()))

The first line works great; I can open regedit and see the key.  The second
and fourth lines are throwaway, just to let me see the final execution
time.  The problem therefore lies with the third line (SendMessage).

Just to verify I've got things right, I have the following declarations
inside the class, right above my Form_Load declaration:

   Private Const WM_SETTINGCHANGE As Integer = &H1A
   Private Shared ReadOnly HWND_BROADCAST As New IntPtr(-1)

   Private Declare Auto Function SendMessage Lib "User32" ( _
    ByVal hWnd As IntPtr, _
    ByVal Msg As Integer, _
    ByVal wParam As IntPtr, _
    ByVal lParam As String) As Integer
Scott McNair - 06 Mar 2008 22:57 GMT
> Just to make sure, I started the app and let it sit there, to see how
> long it would take (if ever) to execute.  So far it's been sitting for
> about ten minutes.

As a followup:

Rather than run the app in debug mode has I had been doing, I compiled it
as a release, and then ran that app.  It ran within a second, but it
returned nothing in the MsgBox that supposedly is polling the environment
variable.

I then ran it again, and it returned the proper string in the MsgBox.  I
then went into the app and disabled the code that sets the variable,
effectively having the MsgBox be my first line; it still reported the
variable.

So I decided to run it again.  I deleted the value from the registry and
reran the application.  This time it reported the value properly on the
first execution.

I continued my experiment.  I deleted the key and I remarked everything
out.  I recompiled the app, and ran it.  It still reported the key.  "No
problem," I thought, "it just hasn't sent the environment refresh."

So this time I left the registry write remarked, but I unremarked the
SendMessage line.  I ran it again, and it STILL reported C:\Program Files
\TCS\ as the value of the variable, even though it shouldn't be there.

The only explanation I can think of is that the SendMessage command only
updates and inserts, but it doesn't actually clear removed items from the
current environment.

Does that sound about right?
Scott McNair - 06 Mar 2008 23:07 GMT
> The only explanation I can think of is that the SendMessage command
> only updates and inserts, but it doesn't actually clear removed items
> from the current environment.

Yet more followup:

If I run the app and declare the variable, it does not see the variable
within that instance of the app.  I set a timer for five seconds to enable
immediately after SendMessage, and then MsgBoxed the variable; it showed a
blank.

If I then uncomment the code that creates the variable, and recompile the
app, the variable is there when I run it.

I'm guessing that's not typical execution, but I've run it about three or
four times, with the same result each time.
Tom Shelton - 06 Mar 2008 23:44 GMT
>> The only explanation I can think of is that the SendMessage command
>> only updates and inserts, but it doesn't actually clear removed items
[quoted text clipped - 12 lines]
> I'm guessing that's not typical execution, but I've run it about three or
> four times, with the same result each time.

Scott...  I can play with this a little more - but, I want to ask before
we go much further (probably should have done this first!), but what is
the ultimate goal here?  We maybe going down the wrong road :)

Signature

Tom Shelton

Scott McNair - 07 Mar 2008 14:19 GMT
> Scott...  I can play with this a little more - but, I want to ask before
> we go much further (probably should have done this first!), but what is
> the ultimate goal here?  We maybe going down the wrong road :)

Hi Tom,

The goal is two-fold.  

Firstly, we plan to use the path for installation of our suite of apps.  

Secondly, we plan to use the environment variable as an encryption hash for
sensitive data, such as passwords stored within xml, database passwords
stored in the registry, etc.

There may be a better way to do these things, but my boss is absolutely
sold on the concept of using environment variables, so that's the way we're
going.

Regards,
Scott
Tom Shelton - 07 Mar 2008 15:07 GMT
>> Scott...  I can play with this a little more - but, I want to ask before
>> we go much further (probably should have done this first!), but what is
[quoted text clipped - 16 lines]
> Regards,
> Scott

I guess what I'm asking is - are we trying to make this a permenant
system wide variable, or only need it to go to child processes?
Because, you can add them to you child environment when they are
starting if you use System.Diagnostics.Process class to start them...

Anyway - I think the behavior your seeing is consistant, with the way
things work.  I'll try and post a complete sample here pretty soon.  
By the way, if you only want the variable for the current user you
can put them in HKEY_CURRENT_USER\Environment.

Signature

Tom Shelton

Scott McNair - 07 Mar 2008 15:16 GMT
> I guess what I'm asking is - are we trying to make this a permenant
> system wide variable, or only need it to go to child processes?
> Because, you can add them to you child environment when they are
> starting if you use System.Diagnostics.Process class to start them...

The variable would be permanent and persistent.

> Anyway - I think the behavior your seeing is consistant, with the way
> things work.  I'll try and post a complete sample here pretty soon.  
> By the way, if you only want the variable for the current user you
> can put them in HKEY_CURRENT_USER\Environment.

It'd be a system-wide variable, so that any user with any login would have
access to this variable.

By the way, thanks for all your help, Tom.  You've saved me hours of
fruitless googling.

Regards,
Scott
Tom Shelton - 07 Mar 2008 20:28 GMT
On Mar 7, 8:16 am, Scott McNair
<smcn...@beachexpress.takethispartout.com> wrote:

> > I guess what I'm asking is - are we trying to make this a permenant
> > system wide variable, or only need it to go to child processes?
[quoted text clipped - 16 lines]
> Regards,
> Scott

Option Explicit On
Option Strict On
Option Infer Off

Imports System
Imports System.Runtime.InteropServices
Imports Microsoft.Win32

Public Class MainForm
   Private Shared ReadOnly HWND_BROADCAST As New IntPtr(-1)
   Private Const WM_SETTINGCHANGE As Integer = &H1A

   Private Declare Auto Function SendMessage Lib "user32" ( _
       ByVal hWnd As IntPtr, _
       ByVal Msg As Integer, _
       ByVal wParam As IntPtr, _
       ByVal lParam As String) As Integer

   Private Sub MainForm_Load(ByVal sender As Object, ByVal e As
System.EventArgs) Handles Me.Load
       LoadEnvironment()
   End Sub

   Private Sub LoadEnvironment()
       Try
           ListView1.BeginUpdate()

           ListView1.Items.Clear()

           Dim keys As New List(Of String)()
           For Each target As EnvironmentVariableTarget In
DirectCast([Enum].GetValues(GetType(EnvironmentVariableTarget)),
EnvironmentVariableTarget())
               For Each entry As DictionaryEntry In
Environment.GetEnvironmentVariables(target)
                   If Not keys.Contains(entry.Key.ToString()) Then
                       keys.Add(entry.Key.ToString())
                       Dim item As New ListViewItem(New String()
{entry.Key.ToString(), entry.Value.ToString()})
                       ListView1.Items.Add(item)
                   End If
               Next
           Next

       Catch
       Finally
           ListView1.EndUpdate()
       End Try
   End Sub

   Private Sub btnAdd_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnAdd.Click
       Dim key As RegistryKey = OpenKey()
       key.SetValue("Baloney", "Oscar Meyer",
RegistryValueKind.String)
       key.Close()
       SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, IntPtr.Zero,
"Environment")
   End Sub

   Private Sub btnDelete_Click(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles btnDelete.Click
       Dim key As RegistryKey = OpenKey()
       key.DeleteValue("Baloney", False)
       key.Close()
       SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, IntPtr.Zero,
"Environment")
   End Sub

   Private Function OpenKey() As RegistryKey
       Return Registry.LocalMachine.OpenSubKey("System
\CurrentControlSet\Control\Session Manager\Environment", True)
   End Function

   Protected Overrides Sub WndProc(ByRef m As
System.Windows.Forms.Message)
       If m.Msg = WM_SETTINGCHANGE AndAlso
Marshal.PtrToStringAuto(m.LParam) = "Environment" Then
           LoadEnvironment()
       End If
       MyBase.WndProc(m)
   End Sub

End Class

Basically a form with a listview and a couple of buttons.  the
listview is in details view and has to columns, name and value.  It
appears that the System.Environment.GetVariables() won't refresh
unless you pass in the target type.  So, I do that, but make sure
their are no duplicates in the final list....

Kind of rough, but it seems to work ok :)  At least on XP - I suspect
you might have permission issues on Vista ;)

--
Tom Shelton
Scott McNair - 07 Mar 2008 20:44 GMT
Tom Shelton <tom_shelton@comcast.net> wrote in news:928f4a03-d99d-4d8b-
93a1-3477620bb597@d62g2000hsf.googlegroups.com:

> Kind of rough, but it seems to work ok :)  At least on XP - I suspect
> you might have permission issues on Vista ;)

Thank you :)
Andrew Backer - 06 Mar 2008 20:58 GMT
Take a look at this, which might help you.  It may come down to updating
the registry.

http://ghouston.blogspot.com/2005/08/how-to-create-and-change-environment.html

> Hi,
>
[quoted text clipped - 21 lines]
> Regards,
> Scott

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.