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 / C# / February 2008

Tip: Looking for answers? Try searching our database.

Winforms, Shown Event and SetEnvironmentVariable

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Dilip - 14 Feb 2008 21:50 GMT
I am running into a weird problem in my ultra-simple Winforms
application written in C#.

In the Form.Shown event I set a couple of environment variables using
the standard SetEnvironmentVariable API like so:

Environment.SetEnvironmentVariable("someKey", somevalue,
EnvironmentVariableTarget.User);

I have 2 such calls.  Amazingly it takes nearly 10 seconds for these
two calls to execute!  If I comment out these 2 calls and run, the
application is just spiffy and the dialog comes up in no time.
Because it takes 10 seconds for these calls to execute, the dialog
kinda hangs before becoming responsive for that duration of time
(obviously because the UI thread is held up).

Am I doing something wrong?
Dilip - 14 Feb 2008 22:06 GMT
> I am running into a weird problem in my ultra-simple Winforms
> application written in C#.
[quoted text clipped - 13 lines]
>
> Am I doing something wrong?

Apologies.. false alarm!
It was a different problem.
Peter Duniho - 14 Feb 2008 22:21 GMT
> Apologies.. false alarm!
> It was a different problem.

What was it?  As I mentioned, I was able to easily reproduce what you  
described.  Are you saying that you're not actually having that problem?

Pete
Dilip - 15 Feb 2008 13:34 GMT
On Feb 14, 4:21 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
> > Apologies.. false alarm!
> > It was a different problem.
[quoted text clipped - 3 lines]
>
> Pete

Peter
I am sorry once again.  Its now a false alarm on top of a false
alarm :-)
My original post was accurate.  Those two calls to the
SetEnvironmentVariable does take nearly 10 seconds to execute (I timed
it with System.Diagnostics.Stopwatch).

This is weird because I earlier had these calls in a console app and I
never saw this delay.  Putting them in a Winforms app however
introduces it.  I can't understand why.

I am going to run CLR profiler and see what is bottlenecking it.  I
haven't read your other post yet.
Will get to it after I post this.
Peter Duniho - 14 Feb 2008 22:20 GMT
> [...]
> In the Form.Shown event I set a couple of environment variables using
[quoted text clipped - 7 lines]
>
> Am I doing something wrong?

You mean, other than setting an environment variable?  :)

I'm surprised it takes 10 seconds for the calls to execute.  I'd agree  
that seems unreasonably long.  However, I can easily reproduce the exact  
behavior (almost down to the time...11 seconds on my computer, though I  
did see it take "only" 8 seconds once).

Also surprising is that I wasn't able to find any mention of this issue  
using Google.  I tried a few different searches and a quick look at the  
results turned up no other mentions of the delay.  It makes me wonder if  
this is a new problem, possibly related to a recent Windows Update.

But why are you setting environment variables anyway?  That's kind of an  
archaic thing to do.  Do you have a requirement for compatibility with  
some older software that uses the variables?

As far as dealing with the issue: I think the best solution is "don't do  
that".  That is, don't use environment variables if you don't absolutely  
have to.  I think the alternative (short of figuring out why it takes so  
long and possibly finding an alternative) would be to move those  
operations out of the GUI thread.  You can use the BackgroundWorker class  
to execute them using the thread pool and then notify your Form class when  
the operation is done (so that it can update itself as appropriate).

One thing I didn't try was using unmanaged code to set the environment  
variables.  That's something you might try, in order to at least  
understand if the issue is something unique to .NET, or is a general  
problem with setting environment variables.  And if it is significantly  
faster using unmanaged code, you might try using p/invoke with the  
unmanaged API to set the variables rather than going through .NET.

Pete
Dilip - 15 Feb 2008 14:03 GMT
On Feb 14, 4:20 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
> > [...]
> > In the Form.Shown event I set a couple of environment variables using
[quoted text clipped - 9 lines]
>
> You mean, other than setting an environment variable?  :)

> I'm surprised it takes 10 seconds for the calls to execute.  I'd agree
> that seems unreasonably long.  However, I can easily reproduce the exact
[quoted text clipped - 9 lines]
> archaic thing to do.  Do you have a requirement for compatibility with
> some older software that uses the variables?

Nope.. no such requirement.  Its just that my application is kinda
funny in the sense it runs multiple times with different command line
parameters.  I had to maintain some state between invocations.  I
could have used the registry obviously but went the Environment
variable route for no particular reason.  As I said I initially built
this as a console application in C# for easy testing.  Once I was sure
everything is working fine I built an UI around it -- which brings me
to your next point...

> As far as dealing with the issue: I think the best solution is "don't do
> that".  That is, don't use environment variables if you don't absolutely
[quoted text clipped - 3 lines]
> to execute them using the thread pool and then notify your Form class when
> the operation is done (so that it can update itself as appropriate).

... I do exactly this :-)  The functionality I tested when my app was
still a console app has been nicely wrapped up in a BackgroundWorker
class.  Its just that setting the environment variable didn't strictly
belong there.  So I set it before invoking
BackgroundWorker.RunAsync(...).  Little did I realize that these
SetEnvironmentVariable calls will take up so much time.  For the
moment I put them in Form.Load event, so the the form doesn't even
show up until after the variables are set.

But I am still curious as to why this problem is not cropping up with
a plain vanilla console application!

This also brings up a related question.  The UI and this functionality
are two separate beasts.  The goal is I must be able to rip out this
functionality and use it elsewhere (maybe as a standalone console app)
without worrying about tightly-binding it to the UI logic.  However
the problem is if I use the BackgroundWorker class and if I want to
report the progress percentage to the UI from the functionality, I
have no choice but to pass a reference to the BackgroundWorker class
to the said functionality, right?  Do I now strongly-couple UI with
business logic?
Peter Duniho - 15 Feb 2008 23:35 GMT
> [...]
>> But why are you setting environment variables anyway?  That's kind of an
[quoted text clipped - 6 lines]
> could have used the registry obviously but went the Environment
> variable route for no particular reason.

Well, the environment variables wind up in the registry anyway.  IMHO, if  
that's acceptable to you, you should probably just use the registry  
directly.

In a .NET application, the other alternative would be a configuration  
file.  In .NET 2.0 and later, the Settings class provides a very nice,  
easy way to persist user-specific data and IMHO would be a much better  
solution than using environment variables.

> [...]
> But I am still curious as to why this problem is not cropping up with
> a plain vanilla console application!

I'm curious too.  There's probably a reasonably obvious explanation for  
someone who knows more about the exact implementation.  I did notice when  
I was looking into this yesterday that the unmanaged Win32 API doesn't  
actually provide for this functionality.  The docs say to implement it  
yourself by saving the data to the registry directly, and then  
broadcasting a WM_SETTINGCHANGED message.

Assuming .NET took that advice, it makes me wonder if there's some sort of  
interaction with the broadcast of that message, but I don't know what it  
would be.  Possibly the broadcast has to wait for a timeout because your  
application is stuck trying to change the registry and can't receive it?  
That would explain why the console application works fine, as it may skip  
the window message broadcasting, or at least not having a window itself  
would not wind up being a recursive bottleneck in the broadcast.  It would  
also be consistent with the delay being practically identical on my  
computer as on yours (i.e. it's not dependent on hardware configuration,  
but rather some built-in timing issue).

Of course, under that theory it should be the case that once the setting  
of the registry settings are moved to another thread, it should not take  
so long.  So, I tried that.  And in fact, doing so makes it work a _lot_  
faster.  It's still slower than I'd think, but on my computer it completes  
in between eight to nine tenths of a second when executing the environment  
variables on a separate thread.  Given all the overhead for dealing with  
the broadcast of the window message, thread context switches, etc. maybe  
that's not an unreasonable amount of time.  It's definitely a lot better  
than 10 seconds.  :)

So: have I proved what's going on?  Nope...I still don't really know  
what's going on.  But there's some decent evidence in favor of my theory.  
:)

> This also brings up a related question.  The UI and this functionality
> are two separate beasts.  The goal is I must be able to rip out this
[quoted text clipped - 4 lines]
> have no choice but to pass a reference to the BackgroundWorker class
> to the said functionality, right?

I'm not sure exactly what you mean, but generally the answer is "no".  
BackgroundWorker does not depend on a GUI at all.  You do not need to  
subscribe to the ProgressChanged event, and even if you do, the subscriber  
does not need to be a GUI component.  Without the synchronization context  
that the GUI provides, the event will be raised in the same thread doing  
the work, rather than marshaled over to the GUI thread.  But otherwise it  
works fine.

> Do I now strongly-couple UI with business logic?

That shouldn't be necessary.  If you still think it is, maybe you can  
explain in greater detail why you think it is.  That would help provide  
the context so that I or someone else can better explain why it's not.  :)

Pete
Willy Denoyette [MVP] - 16 Feb 2008 17:24 GMT
> On Feb 14, 4:20 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
> wrote:
[quoted text clipped - 65 lines]
> to the said functionality, right?  Do I now strongly-couple UI with
> business logic?

I can't repro this using a minimal Forms applications that sets two
environment variables in the Shown handler.
The SetEnvironmentVariable calls take less than 2 millisecond. to complete.
Are you running in a local account, or are you running in a domain account?
What version of the framework and OS are you running?

Willy.
Peter Duniho - 16 Feb 2008 18:47 GMT
> I can't repro this using a minimal Forms applications that sets two  
> environment variables in the Shown handler.
[quoted text clipped - 3 lines]
> account?
> What version of the framework and OS are you running?

I was able to reproduce the behavior easily.  So, from my configuration:

Windows XP SP2, IE7 (it shouldn't matter, but as we know it sometimes  
does), all critical updates installed (including this month's release).  
.NET 2.0 installed (SP1, if I recall correctly).  User is a  
restricted/limited user, local account, and the target for the call to  
SetEnvironmentVariable is EnvironmentVariableTarget.User.

As I noted in a different message, running the code in the GUI thread  
results in a 10 second delay (I didn't measure the two calls  
independently, so I don't know if it's a single 10 second delay, or two 5  
second delays).  Running the same exact code in a thread pool thread (via  
BackgroundWorker) results in a much smaller delay (700-900ms...still  
longer than I'd expected, but much more acceptable).

Are you sure you're using the EnvironmentVariableTarget.User as the target  
in your tests?

Pete
Willy Denoyette [MVP] - 16 Feb 2008 21:42 GMT
>> I can't repro this using a minimal Forms applications that sets two
>> environment variables in the Shown handler.
[quoted text clipped - 21 lines]
> Are you sure you're using the EnvironmentVariableTarget.User as the target
> in your tests?

Yep, these two:
Environment.SetEnvironmentVariable("someKey", "1",
EnvironmentVariableTarget.User);
Environment.SetEnvironmentVariable("someOtherKey", "2",
EnvironmentVariableTarget.User);

in Shown handler.

Running V2 SP1 of the FW on VISTA.
Timing done using "QueryThreadCycleTime" API (Vista and up), with Processor
clock at fixed rate.
Total time for the two consecutive calls: ~3.6 msec. on 2.2Ghz Dual core
AMD64
~3 msec. on 3GHz Intel Core Duo.

Willy.
Peter Duniho - 17 Feb 2008 00:49 GMT
> Yep, these two:
> Environment.SetEnvironmentVariable("someKey", "1",  
[quoted text clipped - 7 lines]
> Timing done using "QueryThreadCycleTime" API (Vista and up), with  
> Processor clock at fixed rate.

Why are you doing that?  The question here is elapsed time, not the CPU  
time consumed by the thread for the calls.

If you just put a Stopwatch in the Shown event handler, start it before  
the two calls, and check the Elapsed time after them, what results do you  
get?

Not that it's relevant to this question IMHO, but what's the .NET API for  
the QueryThreadCycleTime call (if any)?  I can only find the unmanaged  
version.  Is there a managed way to get at that?  Maybe in WMI?

Pete
Willy Denoyette [MVP] - 17 Feb 2008 17:45 GMT
>> Yep, these two:
>> Environment.SetEnvironmentVariable("someKey", "1",
[quoted text clipped - 10 lines]
> Why are you doing that?  The question here is elapsed time, not the CPU
> time consumed by the thread for the calls.

One reason is higher precision, initially I used Stopwatch and soon found
out that the elapsed time was way below 1 second (see later), also, I don't
like to use Stopwatch for anything that takes less than a second.
The other reason is that I wanted to measure the time taken by the
*current* UI thread to perform these two API calls, not the time taken by
the other threads in the system. The reason is that SetEnvironmentVariable
calls Win32's "SendMessageTimeout" to broadcast a message to all top level
windows (except the owning window)  and does not return before the message
has been processed by all *other* top level windows or after a 1000 msec.
time-out period (per window). When the system broadcasts a message to a
top-level window who's thread doesn't pump it's message queue, it will wait
a max of 5 seconds before returning, which looks like what's happening in
your (and the OP's) case, though I don't understand why it's working from a
console app.

> If you just put a Stopwatch in the Shown event handler, start it before
> the two calls, and check the Elapsed time after them, what results do you
> get?

~90-100 msecs. using ...
double elapsed = ((double)sw.ElapsedTicks/swFrequency);
with ~10 top-level windows.
This is considerably longer merely because of the extra thread switches

> Not that it's relevant to this question IMHO, but what's the .NET API for
> the QueryThreadCycleTime call (if any)?  I can only find the unmanaged
> version.  Is there a managed way to get at that?  Maybe in WMI?

QueryThreadCycleTime, QueryProcessCycleTime, QueryIdleProcessorCycleTime and
a couple of others are new Win32 API's in Vista and up.
.NET lags behind here, so the only way to use these high precision low
latency counters is by PInvoke.
WMI does/can't expose this, but the VS profiler can be configured to use
these counters, also ETW uses the high precision counters on Vista and
WS2008.

Willy.
Willy Denoyette [MVP] - 17 Feb 2008 18:03 GMT
>>> Yep, these two:
>>> Environment.SetEnvironmentVariable("someKey", "1",
[quoted text clipped - 48 lines]
>
> Willy.

Please note that I don't have handlers for WM_SETTINGCHANGE in the other
running windows applications, other than the default handler.

Willy.
Dilip - 17 Feb 2008 04:26 GMT
On Feb 16, 12:47 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
> As I noted in a different message, running the code in the GUI thread
> results in a 10 second delay (I didn't measure the two calls
> independently, so I don't know if it's a single 10 second delay, or two 5
> second delays).

I can confirm that its two 5-second delay.

The funny thing is I can't glean anything useful out of CLR profiler.
I thought I'd chase the calls and see exactly what is taking so long
but didn't have much success.

BTW, Willy seems to have tested this in Vista.  I haven't run it there
yet -- my problem was exhibited in Windows XP.  I don't have .NET 2.0
SP1 installed.

THe Settings class seems like a nice idea (yet another thing I can
claim to know :-)).  I am going down that road but I'd be curious to
know what the problem is though.  As of now your explanation in
another post seems to make sense to me.

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.