New information has been added to this article since publication.
Refer to the Editor's Update below.

.NET Matters

Const in C#, Exception Filters, IWin32Window, and More

Stephen Toub

Welcome to .NET Matters. This new column will delve into the ins and outs of the Microsoft® .NET Framework, answering readers' questions on various topics related to its extensive libraries, languages, and the common language runtime. If you have a question you'd like answered, feel free to contact us at netqa@microsoft.com. In the meantime, sit back, relax, learn, and enjoy.

Q Are const variables in C# stored in a global location? Can you tell me what are the performance and memory advantages of using a const in a class?

Q Are const variables in C# stored in a global location? Can you tell me what are the performance and memory advantages of using a const in a class?

A Very similar to a #define in C, const "variables" in the .NET Framework don't have their own actual storage location but rather are substituted into the Microsoft Intermediate Language (MSIL) instructions at compile time where they are referenced. For example, if I have the following C# code

int myInt = 5; Console.WriteLine(myInt);

csc.exe will generate this MSIL:

ldc.i4.5 stloc.0 ldloc.0 call void [mscorlib]System.Console::WriteLine(int32)

In other words, it loads the value 5, stores it to the myInt variable, then loads this value back onto the execution stack, and prints it out using Console.WriteLine.

A Very similar to a #define in C, const "variables" in the .NET Framework don't have their own actual storage location but rather are substituted into the Microsoft Intermediate Language (MSIL) instructions at compile time where they are referenced. For example, if I have the following C# code

int myInt = 5; Console.WriteLine(myInt);

csc.exe will generate this MSIL:

ldc.i4.5 stloc.0 ldloc.0 call void [mscorlib]System.Console::WriteLine(int32)

In other words, it loads the value 5, stores it to the myInt variable, then loads this value back onto the execution stack, and prints it out using Console.WriteLine.

If you change the myInt variable to be a constant, like so

const int myInt = 5; Console.WriteLine(myInt);

the MSIL generated will be:

ldc.i4.5 call void [mscorlib]System.Console::WriteLine(int32)

Now, wherever myInt is referenced in the code, instead of having to do a "ldloc.0" to get the value from the variable, the MSIL just loads the constant value which is hardcoded into the MSIL. As such, there's usually a small performance and memory advantage to using constants. However, in order to use them you must have the value of the variable at compile time, and any references to this constant at compile time, even if they're in a different assembly, will have this substitution made.

Constants are certainly a useful tool if you know the value at compile time. If you don't, but want to ensure that your variable is set only once, you can use the readonly keyword in C# (which maps to initonly in MSIL) to indicate that the value of the variable can only be set in the constructor; after that, it's an error to change it. This is often used when a field helps to determine the identity of a class, and is often set equal to a constructor parameter.

Q In Visual C++® .NET and Visual Basic® .NET, I can use exception filters with my catch blocks to determine which exceptions should be caught by a catch block (using more than just the type of the exception). How can I do this in C#?

Q In Visual C++® .NET and Visual Basic® .NET, I can use exception filters with my catch blocks to determine which exceptions should be caught by a catch block (using more than just the type of the exception). How can I do this in C#?

[Editor's Update - 3/21/2004: This answer concerns user filters, the kind of filter generally implied by the term "exception filter". C# does not support user filters. As shown in the example, it does support type filters.] In all honesty, though, most applications that you write will not require exception filters. And if you find yourself in a situation where you think you need them, it's certainly possible to get close with a little bit more code. For example, let's say you have the following code in Visual Basic .NET:

Try ' do something that could throw an exception Catch e As FileNotFoundException When MyFilterMethod(e) ' ••• Catch e As DivideByZeroException ' ••• End Try

[Editor's Update - 3/21/2004: This answer concerns user filters, the kind of filter generally implied by the term "exception filter". C# does not support user filters. As shown in the example, it does support type filters.] In all honesty, though, most applications that you write will not require exception filters. And if you find yourself in a situation where you think you need them, it's certainly possible to get close with a little bit more code. For example, let's say you have the following code in Visual Basic .NET:

Try ' do something that could throw an exception Catch e As FileNotFoundException When MyFilterMethod(e) ' ••• Catch e As DivideByZeroException ' ••• End Try

This code has two catch blocks. The first one only catches FileNotFoundExceptions and only when the method MyFilterMethod returns true when the caught exception is passed to it. If the first catch block cannot handle the exception, the second one, which handles all DivideByZeroExceptions, will be given a chance.

C# doesn't support exception filters, so you'd need to write equivalent code that resembles Figure 1. Here, I combine all of the catch blocks I had in the previous snippet into a single catch block in my C# code. Then I manually test the exception against the exception types and filters and act accordingly. If none of my virtual catch blocks match, I rethrow the exception (note that I use "throw" rather than "throw e" so as not to rewrite the StackTrace contained in the exception).

Figure 1 Simulating Exception Filters in C#

try { // do something that could throw an exception } catch(Exception e) { if (e is FileNotFoundException && MyFilterMethod((FileNotFoundException)e)) { // ••• } else if (e is DivideByZeroException) { // ••• } else throw; } // or alternatively using specific type filters, as // the caught exception types are unrelated by inheritance try { // do something that could throw an exception } catch(FileNotFoundException e) { if (MyFilterMethod(e)) { // ••• } else throw; } catch(DivideByZeroException e) { // ••• }

It is true that C# does not support exception handlers, but as shown in Figure 1 it doesn't mean it is any less capable. This just happens to be one case in which Visual Basic .NET provides a simpler syntax to express a concept than does C#.

Q I'm writing a Windows® Forms application that runs in the system tray and displays message boxes to the user every now and then. Unfortunately, these message boxes are often covered up by other windows on the desktop, so I need to find a way to display my message box parented by whatever is the foreground window. In Win32®, I know I can use the GetForegroundWindow function to get a handle to the window with which the user is currently working. I can use interop to call this function, but it gives me back a handle and I have no idea how to use that in Windows Forms. Do you have any suggestions?

Q I'm writing a Windows® Forms application that runs in the system tray and displays message boxes to the user every now and then. Unfortunately, these message boxes are often covered up by other windows on the desktop, so I need to find a way to display my message box parented by whatever is the foreground window. In Win32®, I know I can use the GetForegroundWindow function to get a handle to the window with which the user is currently working. I can use interop to call this function, but it gives me back a handle and I have no idea how to use that in Windows Forms. Do you have any suggestions?

A Windows Forms provides the IWin32Window interface for just this purpose. This interface is implemented by objects that expose Win32 HWND handles, such as System.Windows.Forms.Control, from which System.Windows.Forms.Form is derived. As such, you need to wrap the P/Invoke to GetForegroundWindow with a class that implements IWin32Window. A complete sample implementation is shown in Figure 2.

A Windows Forms provides the IWin32Window interface for just this purpose. This interface is implemented by objects that expose Win32 HWND handles, such as System.Windows.Forms.Control, from which System.Windows.Forms.Form is derived. As such, you need to wrap the P/Invoke to GetForegroundWindow with a class that implements IWin32Window. A complete sample implementation is shown in Figure 2.

Figure 2 Implementing IWin32Window

public class ForegroundWindow : IWin32Window { private static ForegroundWindow _window = new ForegroundWindow(); private ForegroundWindow(){} public static IWin32Window Instance { get { return _window; } } [DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow(); IntPtr IWin32Window.Handle { get { return GetForegroundWindow(); } } }

Now you can display a message box that uses the foreground window as a parent using code like the following:

MessageBox.Show(ForegroundWindow.Instance, "Displayed on top!");

The message box retrieves the handle from ForegroundWindow using the IWin32Window.Handle property, which in turn calls to GetForegroundWindow to retrieve the appropriate handle. This technique could also be used with functions like GetActiveWindow, GetDesktopWindow, FindWindow, or any other piece of code that results in a valid HWND.

[Editor's Update - 3/21/2004: Static classes prevent all instantiations. One would not be helpful in this particular scenario as ForegroundWindow needs to privately instantiate itself.]

Q Does every keyword in C# have an equivalent keyword in MSIL? For example, to what does the using keyword map? I wasn't able to find anything that matched.

Q Does every keyword in C# have an equivalent keyword in MSIL? For example, to what does the using keyword map? I wasn't able to find anything that matched.

A Everything written in C# needs to be expressable in MSIL as the C# compiler targets it, but that doesn't mean that there is a one-to-one mapping between C# keywords and MSIL keywords. For example, C# provides high-level looping constructs such as the for loop and the while loop. In MSIL, these concepts are expressed using conditional checks and jumps. The using keyword you mention is syntactic sugar provided in C# that makes it very easy to clean up resources that require disposal (using the IDisposable interface). The following C# code

using (StreamReader reader = new StreamReader(@"C:\test.txt")) { string line = reader.ReadLine(); }

is compiled down to the MSIL shown in Figure 3. If you convert the MSIL back to C#, you get:

StreamReader reader = new StreamReader(@"C:\test.txt"); try { string line = reader.ReadLine(); } finally { if (reader != null) ((IDisposable)reader).Dispose(); }

In other words, the using keyword simply maps to a try/finally construct that ensures the used object is always disposed. The code snippet just shown represents the typical expansion for the using keyword. You should note, however, that if a value type is used instead of a reference type, the compiler will not generate the check for a null value.

A Everything written in C# needs to be expressable in MSIL as the C# compiler targets it, but that doesn't mean that there is a one-to-one mapping between C# keywords and MSIL keywords. For example, C# provides high-level looping constructs such as the for loop and the while loop. In MSIL, these concepts are expressed using conditional checks and jumps. The using keyword you mention is syntactic sugar provided in C# that makes it very easy to clean up resources that require disposal (using the IDisposable interface). The following C# code

using (StreamReader reader = new StreamReader(@"C:\test.txt")) { string line = reader.ReadLine(); }

is compiled down to the MSIL shown in Figure 3. If you convert the MSIL back to C#, you get:

StreamReader reader = new StreamReader(@"C:\test.txt"); try { string line = reader.ReadLine(); } finally { if (reader != null) ((IDisposable)reader).Dispose(); }

In other words, the using keyword simply maps to a try/finally construct that ensures the used object is always disposed. The code snippet just shown represents the typical expansion for the using keyword. You should note, however, that if a value type is used instead of a reference type, the compiler will not generate the check for a null value.

Figure 3 'using' Compiled to MSIL

IL_0000: ldstr "C:\\test.txt" IL_0005: newobj instance void [mscorlib]System.IO.StreamReader::.ctor(string) IL_000a: stloc.0 .try { IL_000b: ldloc.0 IL_000c: callvirt instance string [mscorlib]System.IO.TextReader::ReadLine() IL_0011: stloc.1 IL_0012: leave.s IL_001e } // end .try finally { IL_0014: ldloc.0 IL_0015: brfalse.s IL_001d IL_0017: ldloc.0 IL_0018: callvirt instance void [mscorlib]System.IDisposable::Dispose() IL_001d: endfinally } // end handler IL_001e: ...

Q What is the proper way to raise an event in C#? I've heard that I need to be concerned about multithreading issues when doing so.

Q What is the proper way to raise an event in C#? I've heard that I need to be concerned about multithreading issues when doing so.

A If an event in C# has no delegates registered with it, attempting to raise the event will cause a NullReferenceException. As a result, given an event declared as

public event EventHandler MyEvent;

you'll often see it raised with code such as:

if (MyEvent != null) MyEvent(this, EventArgs.Empty);

A If an event in C# has no delegates registered with it, attempting to raise the event will cause a NullReferenceException. As a result, given an event declared as

public event EventHandler MyEvent;

you'll often see it raised with code such as:

if (MyEvent != null) MyEvent(this, EventArgs.Empty);

This works fine in a single-threaded environment, but consider the scenario in which multiple threads are accessing MyEvent simultaneously. In such a case, one thread could check whether MyEvent is null and determine that it isn't. Just after doing so, another thread could remove the last registered delegate from MyEvent. When the first thread attempts to raise MyEvent, an exception will be thrown. A better way to avoid this scenario is shown in the following code snippet:

void MyEventInvoke(object sender, EventArgs args) { EventHandler ev = MyEvent; if (ev != null) ev(sender, args); }

Whenever a delegate is added to or removed from an event using the default implementations of the add and remove accessors, the Delegate.Combine and Delegate.Remove static methods are used. These methods return a new instance of a delegate, rather than modifying the ones passed to it. In addition, assignments of object references in .NET are thread-safe, and the default implementations of the add and remove event accessors are synchronized. As such, the previous code succeeds by first copying the multicast delegate from the event to a temporary variable. Any changes to MyEvent after this point will not affect the copy you've made and stored. You can now safely test whether any delegates were registered and subsequently invoke them.

As an aside, the RaiseEvent keyword in Visual Basic handles the null check for you and, as a result, developers using Visual Basic don't first need to test whether any delegates are registered with an event before raising it in a single-threaded scenario.

Q I'm trying to use the System.Diagnostics.Process class to run the C# compiler csc.exe, but I need to know the full path to the application, which is located in the .NET Framework's installation directory. The System.Environment.SpecialFolder enumeration allows me to get the path to a variety of folders on my system, but not this particular one. Using C#, how can I retrieve the runtime's installation directory? On my system, this is c:\WINDOWS\Microsoft.NET\Framework\v1.1.4322.

Q I'm trying to use the System.Diagnostics.Process class to run the C# compiler csc.exe, but I need to know the full path to the application, which is located in the .NET Framework's installation directory. The System.Environment.SpecialFolder enumeration allows me to get the path to a variety of folders on my system, but not this particular one. Using C#, how can I retrieve the runtime's installation directory? On my system, this is c:\WINDOWS\Microsoft.NET\Framework\v1.1.4322.

A Mscoree.dll exposes a GetCORSystemDirectory method which can be used to retrieve the installation directory for the version of the common language runtime (CLR) that is loaded into the current process, as shown here:

HRESULT GetCORSystemDirectory( LPWSTR pbuffer, DWORD cchBuffer, DWORD* dwlength);

If the CLR is not loaded, it will return the installation directory for the latest version installed.

A Mscoree.dll exposes a GetCORSystemDirectory method which can be used to retrieve the installation directory for the version of the common language runtime (CLR) that is loaded into the current process, as shown here:

HRESULT GetCORSystemDirectory( LPWSTR pbuffer, DWORD cchBuffer, DWORD* dwlength);

If the CLR is not loaded, it will return the installation directory for the latest version installed.

The first parameter, pbuffer, takes a pointer to the string that will hold the path upon the function's return. cchBuffer is the number of characters that can be safely stored in pbuffer, and dwlength is a pointer to an integer that holds the number of characters actually in the path. To use it from C#, you need to use interop:

[DllImport("mscoree.dll")] private static extern int GetCORSystemDirectory( [MarshalAs(UnmanagedType.LPWStr)]StringBuilder pbuffer, int cchBuffer, ref int dwlength);

In the .NET Framework, strings are immutable, meaning that once created, they cannot be changed (some counter this assertion stating that strings can be changed using unsafe code and direct memory access, but doing so is a very bad idea). As such, instead of a String, the first parameter in the P/Invoke declaration is a mutable StringBuilder, marshaled as an unmanaged LPWSTR. You also need to ensure that StringBuilder is large enough to hold the path of the folder, which on a Win32 system is at most 260 characters. The resulting C# method looks like the following:

private static string GetClrInstallationDirectory() { int MAX_PATH = 260; StringBuilder sb = new StringBuilder(MAX_PATH); GetCORSystemDirectory(sb, MAX_PATH, ref MAX_PATH); return sb.ToString(); }

All that said, if you're doing this to access the C# compiler as you say, you should investigate the Microsoft.CSharp.CSharpCodeProvider class, which provides access to instances of the C# code generator and code compiler.

Q While I was using remote desktop to access my machine at home, I accidentally ejected the CD tray. While searching for a tool to close the tray, it occurred to me that this should be possible programmatically (since all of these tools are able to do so). How can I do this from C#?

Q While I was using remote desktop to access my machine at home, I accidentally ejected the CD tray. While searching for a tool to close the tray, it occurred to me that this should be possible programmatically (since all of these tools are able to do so). How can I do this from C#?

A Believe it or not, I've done the same thing multiple times, and while I'm sure nothing would happen to my computer with the CD tray sticking out, it nags at me. There are no .NET libraries in the Framework that provide this functionality, but that doesn't mean you're at an impasse. You can use interop to access the necessary functionality provided by Win32.

A Believe it or not, I've done the same thing multiple times, and while I'm sure nothing would happen to my computer with the CD tray sticking out, it nags at me. There are no .NET libraries in the Framework that provide this functionality, but that doesn't mean you're at an impasse. You can use interop to access the necessary functionality provided by Win32.

The Windows Multimedia API, available in winmm.dll, exposes a method mciSendString which can be used to send a command to a Media Control Interface (MCI) device, such as your computer's CD drive. To use this method in C#, I'll define an interop signature that looks like the following:

[DllImport("winmm.dll", EntryPoint="mciSendStringA", CharSet=CharSet.Ansi)] public static extern int MciSendString(string lpszCommand, StringBuilder lpszReturnString, int cchReturn, IntPtr hwndCallback);

I can then call this with the appropriate command that tells the CD drive to close the tray:

private static void CloseCdTray() { MciSendString("Set cdaudio door closed wait", null, 0, IntPtr.Zero); }

If you have more than one CD drive, you can change the argument to MciSendString to target one in particular. For more information on the Windows multimedia API, see About MCI.

Q I'm writing a C# application to monitor various happenings on my system and I'd like to query for the current CPU consumption. Is this possible?

Q I'm writing a C# application to monitor various happenings on my system and I'd like to query for the current CPU consumption. Is this possible?

A There are probably a few ways to retrieve the data you need, but one easy way is to use performance counters. The System.Diagnostics.PerformanceCounter class allows easy access to system counters as well as to counters you've created for your own applications. The "% Processor Time" counter in the "Processor" category allows you to retrieve the current CPU consumption percentage as a float ranging between 0 and 100.

A There are probably a few ways to retrieve the data you need, but one easy way is to use performance counters. The System.Diagnostics.PerformanceCounter class allows easy access to system counters as well as to counters you've created for your own applications. The "% Processor Time" counter in the "Processor" category allows you to retrieve the current CPU consumption percentage as a float ranging between 0 and 100.

If you're going to be retrieving the usage multiple times, it makes sense to store the PerformanceCounter object so that it doesn't need to be recreated every time you want to retrieve the value, as shown in the code listed in Figure 4.

Figure 4 Querying CPU Usage

private static PerformanceCounter _cpuCounter; private static float CpuUsage { get { if (_cpuCounter == null) { _cpuCounter = new PerformanceCounter( "Processor", "% Processor Time", "_Total", true); } return _cpuCounter.NextValue(); } }

This code delay-loads the PerformanceCounter (so that it isn't instantiated if it's never used), caches it so that you only need to create it once, and then on each request uses the cached counter object to retrieve the next value of the performance counter—that is, the current CPU usage value.

Q I've heard that XmlSerializer generates code dynamically to serialize and deserialize my classes. Is there any way to take a look at the code that it generates?

Q I've heard that XmlSerializer generates code dynamically to serialize and deserialize my classes. Is there any way to take a look at the code that it generates?

A By default, XmlSerializer deletes the code it generates as soon as it is compiled into an assembly. However, the nice developers at Microsoft used a trace switch to allow you to configure this behavior. If you add the following code to your machine.config

<system.diagnostics> <switches> <add name="XmlSerialization.Compilation" value="4"/> </switches> </system.diagnostics>

XmlSerializer will leave behind in your temp directory key files that it generated, including the source code for the custom serializer class. On a machine running Windows XP, the temp directory is available at %TEMP%. After running your app that uses XmlSerializer, inspect the temporary files for a recently created .cs file.

A By default, XmlSerializer deletes the code it generates as soon as it is compiled into an assembly. However, the nice developers at Microsoft used a trace switch to allow you to configure this behavior. If you add the following code to your machine.config

<system.diagnostics> <switches> <add name="XmlSerialization.Compilation" value="4"/> </switches> </system.diagnostics>

XmlSerializer will leave behind in your temp directory key files that it generated, including the source code for the custom serializer class. On a machine running Windows XP, the temp directory is available at %TEMP%. After running your app that uses XmlSerializer, inspect the temporary files for a recently created .cs file.

Send your questions and comments to  netqa@microsoft.com.

Thanks to the following Microsoft developers for their technical expertise: Jay Bazuzi, Eric Gunnerson, Gerrard Lindsay, and Peter Wieland