FREE BOOK

Chapter 10: Processes, AppDomains,Contexts, and Threads

Posted by Apress Free Book | C#.NET February 02, 2009
In this Chapter you drill deeper into the constitution of a .NET executable host and come to understand the relationship between Win32 processes, application domains, contexts, and threads.

Starting and Killing Processes Programmatically

The final aspects of the System.Diagnostics.Process type examined here are the Start() and Kill() methods. As you can gather by their names, these members provide a way to programmatically launch and terminate a process. For example:

      public static void StartAndKillProcess()
        {
            // Launch Internet Explorer.
            Process ieProc = Process.Start("IExplore.exe",
            "www.intertech-inc.com");
            Console.Write("--> Hit enter to kill {0}...", ieProc.ProcessName);
            Console.ReadLine();
            // Kill the iexplorer.exe process.
            try { ieProc.Kill(); }
            catch { } // In case user already killed it...
        }

The static Process.Start() method has been overloaded a few times, however. At minimum you will need to specify the friendly name of the process you wish to launch (such as MS Internet Explorer). This example makes use of a variation of the Start() method that allows you to specify any additional arguments to pass into the program's entry point (i.e., the Main() method).

The Start() method also allows you to pass in a System.Diagnostics.ProcessStartInfo type to specify additional bits of information regarding how a given process should come into life. Here is the formal definition of ProcessStartInfo (see online Help for full details of this type):

public sealed class System.Diagnostics.ProcessStartInfo :object
{
public ProcessStartInfo();
public ProcessStartInfo(string fileName);
public ProcessStartInfo(string fileName, string arguments);
public string Arguments { get; set; }
public bool CreateNoWindow { get; set; }
public StringDictionary EnvironmentVariables { get; }
public bool ErrorDialog { get; set; }
public IntPtr ErrorDialogParentHandle { get; set; }
public string FileName { get; set; }
public bool RedirectStandardError { get; set; }
public bool RedirectStandardInput { get; set; }
public bool RedirectStandardOutput { get; set; }
public bool UseShellExecute { get; set; }
public string Verb { get; set; }
public string[] Verbs { get; }
public ProcessWindowStyle WindowStyle { get; set; }
public string WorkingDirectory { get; set; }
public virtual bool Equals(object obj);
public virtual int GetHashCode();
public Type GetType();
public virtual string ToString();
      }

Regardless of which version of the Process.Start() method you invoke, do note that you are returned a reference to the newly activated process. When you wish to terminate the process, simply call the instance level Kill() method.

SOURCE CODE The ProcessManipulator application is included under the Chapter 10 subdirectory.

Understanding the System.AppDomain Type

Now that you understand how to interact with a Win32 process from managed code, we need to examine more closely the new (but related) concept of a .NET application domain. As I mentioned briefly in the introduction, unlike a traditional (non-.NET) Win32 *.exe application, .NET assemblies are hosted in a logical partition within a process termed an application domain (aka AppDomain) and many application domains can be hosted inside a single OS process. This additional subdivision of a traditional Win32 process offers several benefits, some of which are:

  • AppDomains are a key aspect of the OS-neutral nature of the .NET platform, given that this logical division abstracts away the differences in how an underlying operating system represents a loaded executable.
  • AppDomains are far less expensive in terms of processing power and memory than a full blown process (for example, the CLR is able to load and unload application domains much quicker than a formal process).
  • AppDomains provide a deeper level of isolation for hosting a loaded application. If one AppDomain within a process fails, the remaining AppDomains remain functional.

As suggested in the previous hit-list, a single process can host any number of AppDomains, each of which is fully and completely isolated from other AppDomains within this process (or any other process). Given this factoid, be very aware that applications that run in unique AppDomains are unable to share any information of any kind (global variables or static fields) unless they make use of the .NET Remoting protocol (examined in Chapter 12) to marshal the data.

NOTE In some respects, .NET application domains are reminiscent of the "apartment" architecture of classic COM. Of course, .NET AppDomains are
managed types whereas the COM apartment architecture is built on an unmanaged (and hideously complex) structure.

Understand that while a single process may host multiple AppDomains, this is not always the case. At the very least an OS process will host what is termed the default application domain. This specific application domain is automatically created by the CLR at the time the process launches. After this point, the CLR creates additional application domains on an as-needed basis. If the need should arise (which it most likely will not for a majority of your .NET endeavors), you are also able to programmatically create application domains at runtime within a given process using static methods of the System.AppDomain class. This class is also useful for low-level control of application domains. Key members of this class are shown in Table 10-4.

Table 10-4. Select Members of AppDomain

AppDomain Member Meaning in Life
CreateDomain() This static method creates a new AppDomain in the current process. Understand that the CLR will create new application domains as necessary, and thus the chance of you absolutely needing to call this member is slim to none (unless you happen to be building a custom CLR host).
GetCurrentThreadId() This static method returns the ID of the active thread in the current application domain.
Unload() Another static method that allows you to unload a specified AppDomain within a given process.
BaseDirectory This property returns the base directory that the assembly resolver used to probe for dependent assemblies.
CreateInstance() Creates an instance of a specified type defined in a specified assembly file.
ExecuteAssembly() Executes an assembly within an application domain, given its file name.
GetAssemblies() Gets the set of .NET assemblies that have been loaded into this application domain. Unlike the Process type, the GetAssemblies() method will only return the list of true-blue .NET binaries. COM-based or C-based binaries are ignored.
Load() Used to dynamically load an assembly into the current application domain.

In addition, the AppDomain type also defines a small set of events that correspond to various aspects of an application domain's life-cycle (Table 10-5).

Table 10-5. Events of the AppDomain Type

Events of System.AppDomain Meaning in Life
AssemblyLoad Occurs when an assembly is loaded
AssemblyResolve Occurs when the resolution of an assembly fails
DomainUnload Occurs when an AppDomain is about to be unloaded
ProcessExit Occurs on the default application domain when the default application domain's parent process exits
ResourceResolve Occurs when the resolution of a resource fails
TypeResolve Occurs when the resolution of a type fails
UnhandledException Occurs when an exception is not caught by an event handler

 

Total Pages : 13 34567

comments