During its lifetime, an application runs in a certain environment composed of networks, servers, operating systems, and users. Information about the myriad aspects of this environment is exposed from a combination of compile-time and run-time settings provided by the .NET Framework and Windows. Compile-Time SettingsAssemblies can provide metadata about themselves to the environment, including common details like company name, product name, and version. You edit this information in VS05 by right-clicking your project and choosing Properties | Application | Assembly Information, opening the dialog shown in Figure 15.1. Figure 15.1. Editing Assembly Information
These values are stored in assembly-wide attributes located in a wizard-generated file called AssemblyInfo.cs (in a Windows Forms project's Properties folder): // Properties\AssemblyInfo.cs using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; ... [assembly: AssemblyTitle("CompileTimeSettingsSample Title")] [assembly: AssemblyDescription("CompileTimeSettingsSample Description")] [assembly: AssemblyCompany("CompileTimeSettingsSample Company")] [assembly: AssemblyProduct("CompileTimeSettingsSample Product")] [assembly: AssemblyCopyright("CompileTimeSettingsSample Copyright")] [assembly: AssemblyTrademark("CompileTimeSettingsSample Trademark")] [assembly: ComVisible(true)] [assembly: Guid("fea43d77-40e1-40cf-9367-768ef5bf26d1")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: NeutralResourcesLanguage("en-AU")] The AssemblyXxx attributes are bundled into the Win32 version information for the assembly, as shown by the Version property page of Explorer's file property dialog in Figure 15.2. Figure 15.2. Viewing Assembly DetailsInternal Name, Original File Name, and Language are beyond the reach of .NET, although Internal Name and Original File Name resolve to ApplicationName.exe. The company name, product name, and product version values stored in the AssemblyXxx attributes are also available in the Application class via three static properties: namespace System.Windows.Forms { sealed class Application { ... // Compile-Time Settings public static string CompanyName { get; } // AssemblyCompany public static string ProductName { get; } // AssemblyProduct public static string ProductVersion { get; } // AssemblyFileVersion ... } } You can retrieve the data shown in Figure 15.3 from these properties by using the following code: // MainForm.cs partial class MainForm : Form { public MainForm() { ... this.companyNameTextBox.Text = Application.CompanyName; this.productNameTextBox.Text = Application.ProductName; this.productVersionTextBox.Text = Application.ProductVersion; } } Figure 15.3. AssemblyXxx Attributes Provided by the Application Class
Because several of the AssemblyXxx attributes aren't available from Application, you need to use other techniques to get them, the most common of which relies on reflection:[1]
using System.Reflection; ... string AssemblyDescription() { // Get all Description attributes on this assembly object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes( typeof(AssemblyDescriptionAttribute), false); // If there aren't any Description attributes, return empty string if( attributes.Length == 0 ) return ""; // If there are Description attributes, return the first return ((AssemblyDescriptionAttribute)attributes[0]).Description; } Run-Time SettingsCompile-time settings represent a group of settings that never change after an assembly is deployed to the environment. However, there are many environmental factors that can change for a deployed assembly, and consequently they can't be compiled into an application. Instead, an application must dynamically retrieve them at run time, and there are several classes in the .NET Framework that provide this support. ApplicationOur old friend, the Application class, exposes several such run-time environment settings that generally pertain to what can change about the application itself, within the context of its environment:
namespace System.Windows.Forms { sealed class Application { ... // Run-Time Settings public static string CommonAppDataPath { get; } public static RegistryKey CommonAppDataRegistry { get; } public static CultureInfo CurrentCulture { get; set; } public static InputLanguage CurrentInputLanguage { get; set; } public static string ExecutablePath { get; } public static string LocalUserAppDataPath { get; } public static FormCollection OpenForms { get; } // New public static string SafeTopLevelCaptionFormat { get; set; } public static string StartupPath { get; } public static string UserAppDataPath { get; } public static RegistryKey UserAppDataRegistry { get; } ... } } This information is shown in Figure 15.4. Figure 15.4. Run-Time Settings Exposed by the Application ClassEnvironmentIf you want more environment settings, such as the environment variables or the command line string, you can get them from the Environment object:
namespace System { static class Environment { ... // Properties public static string CommandLine { get; } public static string CurrentDirectory { get; set; } public static bool HasShutdownStarted { get; } public static string MachineName { get; } public static string NewLine { get; } public static OperatingSystem OSVersion { get; } public static int ProcessorCount { get; } // New public static string StackTrace { get; } public static string SystemDirectory { get; } public static int TickCount { get; } public static string UserDomainName { get; } public static bool UserInteractive { get; } public static string UserName { get; } public static Version Version { get; } public static long WorkingSet { get; } ... } ... } The Environment class affords your application the insight garnered by the sample in Figure 15.5. Figure 15.5. Run-Time Settings Exposed by the Environment Class
Environment implements several methods that allow you to inspect and update a few additional environmental settings:
namespace System.Windows.Forms { static class Environment { ... // Methods public static string ExpandEnvironmentVariables(string name); public static string[] GetCommandLineArgs(); public static string GetEnvironmentVariable(string variable); public static string GetEnvironmentVariable( string variable, EnvironmentVariableTarget target); // New public static IDictionary GetEnvironmentVariables(); public static IDictionary GetEnvironmentVariables( EnvironmentVariableTarget target); // New public static string GetFolderPath(SpecialFolder folder); public static string[] GetLogicalDrives(); public static void SetEnvironmentVariable( string variable, string value); // New public static void SetEnvironmentVariable( string variable, string value, EnvironmentVariableTarget target); // New ... } } Several methods are included for dealing with environment variables and for discovering the logical drives mounted on the current machine. GetFolderPath returns the path to one of a variety of special folders, which are discussed later in this chapter. You saw the use of GetCommandLineArgs in Chapter 14: Applications. SystemInformationIf you need run-time access to shell settings, System.Windows.Forms.SystemInformation is for you. SystemInformation exposes more than 100 settings that encompass a wide variety of areas of the environment, from the mouse, keyboard, and monitor configuration, to a myriad of UI element settings and dimensions. Most are settings that an application might need to adapt to; for example, applications that support mouse wheel scrolling need to check whether the machine on which they are executing actually has a mouse with a mouse wheel. Although there are too many settings to show all of them here, the following subset should provide a taste of the kind of information available from SystemInformation: namespace System.Windows.Forms { class SystemInformation { // Selection of settings on offer public static BootMode BootMode { get; } public static Size Border3DSize { get; } public static Size BorderSize { get; } public static int CaretBlinkTime { get; } public static Size CursorSize { get; } public static int DoubleClickTime { get; } public static bool DragFullWindows { get; } public static int FontSmoothingType { get; } public static int IconHorizontalSpacing { get; } public static int IconVerticalSpacing { get; } public static int KeyboardDelay { get; } public static int KeyboardSpeed { get; } public static Font MenuFont { get; } public static int MenuHeight { get; } public static int MenuShowDelay { get; } public static int MonitorCount { get; } public static int MouseSpeed { get; } public static bool MouseWheelPresent { get; } public static bool PenWindows { get; } public static PowerStatus PowerStatus { get; } public static ScreenOrientation ScreenOrientation { get; } public static Rectangle WorkingArea { get; } ... } } ScreenOne special subset of system information pertains to the screen, and is encapsulated by the appropriately named Screen class: namespace System.Windows.Forms { class Screen { // Methods public static Screen FromControl(Control control); public static Screen FromHandle(IntPtr hwnd); public static Screen FromPoint(Point point); public static Screen FromRectangle(Rectangle rect); public static Rectangle GetBounds(Point pt); public static Rectangle GetBounds(Rectangle rect); public static Rectangle GetBounds(Control ctl); public static Rectangle GetWorkingArea(Point pt); public static Rectangle GetWorkingArea(Rectangle rect); public static Rectangle GetWorkingArea(Control ctl); // Properties public static Screen[] AllScreens { get; } public int BitsPerPixel { get; } public Rectangle Bounds { get; } public string DeviceName { get; } public bool Primary { get; } public static Screen PrimaryScreen { get; } public Rectangle WorkingArea { get; } } } Screen is designed to provide information about one or more screens that are connected to the computer. You can use Screen to acquire either a screen or an area of a screen using one of several methods. Figure 15.6 shows the properties for the main screen, as determined by the PrimaryScreen property. Figure 15.6. Details Pertaining to the Primary Screen
SystemEventsIf your application depends on system or screen information to execute or render, it needs to detect when any changes to such information occur to dynamically refresh itself if required. For this, we have the SystemEvents class: namespace Microsoft.Win32 { sealed class SystemEvents { // Events public static event EventHandler DisplaySettingsChanged; public static event EventHandler DisplaySettingsChanging; public static event EventHandler EventsThreadShutdown; public static event EventHandler InstalledFontsChanged; public static event EventHandler PaletteChanged; public static event PowerModeChangedEventHandler PowerModeChanged; public static event SessionEndedEventHandler SessionEnded; public static event SessionEndingEventHandler SessionEnding; public static event SessionSwitchEventHandler SessionSwitch; public static event EventHandler TimeChanged; public static event TimerElapsedEventHandler TimerElapsed; public static event UserPreferenceChangedEventHandler UserPreferenceChanged; public static event UserPreferenceChangingEventHandler UserPreferenceChanging; ... } } The SystemEvents class provides a variety of notifications that it broadcasts when interesting system events take place, including low memory warnings for notebooks, various moments in the life of a shell session, and user changes made to system preferences and display settings specifically. The following example detects system preference and display settings changes: // MainForm.cs using Microsoft.Win32; ... partial class MainForm : Form { public MainForm() { InitializeComponent(); SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged; SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged; } void SystemEvents_UserPreferenceChanged( object sender, UserPreferenceChangedEventArgs e) { // Handle user system setting change MessageBox.Show( "User Preference Changed: " + e.Category.ToString()); } void SystemEvents_DisplaySettingsChanged( object sender, EventArgs e) { // Handle user system setting change MessageBox.Show("Display Settings Changed"); } } The DisplaySettingsChanged event handler isn't passed any useful arguments to describe the type of change, but the UserPreferenceChanged event handler is passed change information stored in the Category property of UserPreferenceChangedEventArgs. Category is of type UserPreferenceCategory, an enumeration that has the following, somewhat coarse-grained, values: namespace Microsoft.Win32 { enum UserPreferenceCategory { Accessibility = 1, Color = 2, Desktop = 3, General = 4, Icon = 5, Keyboard = 6, Menu = 7, Mouse = 8, Policy = 9, Power = 10, Screensaver = 11, Window = 12, Locale = 13, VisualStyle = 14, } } Collectively, the Application, Environment, SystemInformation, Screen, and SystemEvents classes offer a wide variety of environmental information and notifications that Windows Forms applications may need access to, and these classes can almost always save you the effort of writing the code to find it yourself. |