Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / WinForms / Managed / System / WinForms / Application.cs / 9 / Application.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- /* */ namespace System.Windows.Forms { using System.Runtime.Serialization.Formatters; using System.Text; using System.Threading; using System.Configuration.Assemblies; using System.Runtime.InteropServices; using System.Runtime.Remoting; using System.Runtime.ConstrainedExecution; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System; using System.IO; using Microsoft.Win32; using System.Security; using System.Security.Policy; using System.Security.Permissions; using System.Collections; using System.Globalization; using System.Runtime.Versioning; using System.Reflection; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; using System.Windows.Forms.Layout; using System.Windows.Forms.VisualStyles; using File=System.IO.File; using Directory=System.IO.Directory; using System.Deployment.Internal.Isolation; ////// /// public sealed class Application { ///Provides ////// methods and properties /// to manage an application, such as methods to run and quit an application, /// to process Windows messages, and properties to get information about an application. This /// class cannot be inherited. /// /// Hash table for our event list /// static EventHandlerList eventHandlers; static string startupPath; static string executablePath; static object appFileVersion; static Type mainType; static string companyName; static string productName; static string productVersion; static string safeTopLevelCaptionSuffix; static bool useVisualStyles = false; static FormCollection forms = null; private static object internalSyncObject = new object(); static bool useWaitCursor = false; private static bool useEverettThreadAffinity = false; private static bool checkedThreadAffinity = false; private const string everettThreadAffinityValue = "EnableSystemEventsThreadAffinityCompatibility"; ////// /// in case Application.exit gets called recursively /// private static bool exiting; ////// /// Events the user can hook into /// private static readonly object EVENT_APPLICATIONEXIT = new object(); private static readonly object EVENT_THREADEXIT = new object(); // Constant string used in Application.Restart() private const string IEEXEC = "ieexec.exe"; // Constant string used for accessing ClickOnce app's data directory private const string CLICKONCE_APPS_DATADIRECTORY = "DataDirectory"; // Defines a new callback delegate type [EditorBrowsable(EditorBrowsableState.Advanced)] public delegate bool MessageLoopCallback(); ////// /// This class is static, there is no need to ever create it. /// private Application() { } ////// /// public static bool AllowQuit { get { return ThreadContext.FromCurrent().GetAllowQuit(); } } ////// Determines if the caller should be allowed to quit the application. This will return false, /// for example, if being called from a windows forms control being hosted within a web browser. The /// windows forms control should not attempt to quit the application. /// /// ////// internal static bool CanContinueIdle { get { return ThreadContext.FromCurrent().ComponentManager.FContinueIdle(); } } /// Typically, you shouldn't need to use this directly - use RenderWithVisualStyles instead. internal static bool ComCtlSupportsVisualStyles { [ResourceExposure(ResourceScope.None)] get { if (useVisualStyles && OSFeature.Feature.IsPresent(OSFeature.Themes)) { //NOTE: At this point, we may not have loaded ComCtl6 yet, but it will eventually // be loaded, so we return true here. This works because UseVisualStyles, once // set, cannot be turned off. If that changes (unlikely), this may not work. return true; } //to see if we are comctl6, we look for a function that is exposed only from comctl6 // we do not call DllGetVersion or any direct p/invoke, because the binding will be // cached. // The GetModuleHandle function returns a handle to a mapped module without incrementing its reference count. IntPtr hModule = UnsafeNativeMethods.GetModuleHandle(ExternDll.Comctl32); if (hModule != IntPtr.Zero) { try { IntPtr pFunc = UnsafeNativeMethods.GetProcAddress(new HandleRef(null, hModule), "ImageList_WriteEx"); return (pFunc != IntPtr.Zero); } catch { } } else { // Load comctl since GetModuleHandle failed to find it hModule = UnsafeNativeMethods.LoadLibrary(ExternDll.Comctl32); if (hModule != IntPtr.Zero) { try { IntPtr pFunc = UnsafeNativeMethods.GetProcAddress(new HandleRef(null, hModule), "ImageList_WriteEx"); return (pFunc != IntPtr.Zero); } finally { UnsafeNativeMethods.FreeLibrary(new HandleRef(null, hModule)); } } } return false; } } ///Returns True if it is OK to continue idle processing. Typically called in an Application.Idle event handler. ////// /// public static RegistryKey CommonAppDataRegistry { get { return Registry.LocalMachine.CreateSubKey(CommonAppDataRegistryKeyName); } } internal static string CommonAppDataRegistryKeyName { get { string template = @"Software\{0}\{1}\{2}"; return string.Format(CultureInfo.CurrentCulture, template, CompanyName, ProductName, ProductVersion); } } internal static bool UseEverettThreadAffinity { get { if (!checkedThreadAffinity) { checkedThreadAffinity = true; try { //We need access to be able to read from the registry here. We're not creating a //registry key, nor are we returning information from the registry to the user. new RegistryPermission(PermissionState.Unrestricted).Assert(); RegistryKey key = Registry.LocalMachine.OpenSubKey(CommonAppDataRegistryKeyName); if (key != null) { object value = key.GetValue(everettThreadAffinityValue); if (value != null && (int)value != 0) { useEverettThreadAffinity = true; } } } catch (SecurityException) { // Can't read the key: use default value (false) } catch (InvalidCastException) { // Key is of wrong type: use default value (false) } } return useEverettThreadAffinity; } } ///Gets the registry /// key for the application data that is shared among all users. ////// /// public static string CommonAppDataPath { // NOTE : Don't obsolete these. GetDataPath isn't on SystemInformation, and it // : provides the Win2K logo required adornments to the directory (Company\Product\Version) // get { try { if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed) { string data = AppDomain.CurrentDomain.GetData(CLICKONCE_APPS_DATADIRECTORY) as string; if (data != null) { return data; } } } catch (Exception ex) { if (ClientUtils.IsSecurityOrCriticalException(ex)) { throw; } } return GetDataPath(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)); } } ///Gets the path for the application data that is shared among all users. ////// /// public static string CompanyName { get { lock(internalSyncObject) { if (companyName == null) { // custom attribute // Assembly entryAssembly = Assembly.GetEntryAssembly(); if (entryAssembly != null) { object[] attrs = entryAssembly.GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); if (attrs != null && attrs.Length > 0) { companyName = ((AssemblyCompanyAttribute)attrs[0]).Company; } } // win32 version // if (companyName == null || companyName.Length == 0) { companyName = GetAppFileVersionInfo().CompanyName; if (companyName != null) { companyName = companyName.Trim(); } } // fake it with a namespace // won't work with MC++ see GetAppMainType. if (companyName == null || companyName.Length == 0) { Type t = GetAppMainType(); if (t != null) { string ns = t.Namespace; if (!string.IsNullOrEmpty(ns)){ int firstDot = ns.IndexOf("."); if( firstDot != -1 ){ companyName = ns.Substring(0, firstDot); } else{ companyName = ns; } } else { // last ditch... no namespace, use product name... // companyName = ProductName; } } } } } return companyName; } } ///Gets the company name associated with the application. ////// /// public static CultureInfo CurrentCulture { get { return Thread.CurrentThread.CurrentCulture; } set { Thread.CurrentThread.CurrentCulture = value; } } ///Gets /// or sets the locale information for the current thread. ////// /// public static InputLanguage CurrentInputLanguage { get { return InputLanguage.CurrentInputLanguage; } set { Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "AffectThreadBehavior Demanded"); IntSecurity.AffectThreadBehavior.Demand(); InputLanguage.CurrentInputLanguage = value; } } internal static bool CustomThreadExceptionHandlerAttached { get { return ThreadContext.FromCurrent().CustomThreadExceptionHandlerAttached; } } ///Gets or /// sets the current input language for the current thread. ////// /// /// SECREVIEW ReviewImperitiveSecurity: /// vulnerability to watch out for: A method uses imperative security and might be constructing the permission using state information or return values that can change while the demand is active. /// reason for exclude: the return value of GetModuleFileName shouldnt change between when we called it and when we demanded permissions. [SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")] public static string ExecutablePath { get { if (executablePath == null) { Assembly asm = Assembly.GetEntryAssembly(); if (asm == null) { StringBuilder sb = new StringBuilder(NativeMethods.MAX_PATH); UnsafeNativeMethods.GetModuleFileName(NativeMethods.NullHandleRef, sb, sb.Capacity); executablePath = IntSecurity.UnsafeGetFullPath(sb.ToString()); } else { String ecb = asm.EscapedCodeBase; Uri codeBase = new Uri(ecb); if (codeBase.Scheme == "file") { executablePath = NativeMethods.GetLocalPath(ecb); } else { executablePath = codeBase.ToString(); } } } Uri exeUri = new Uri(executablePath); if (exeUri.Scheme == "file") { Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "FileIO(" + executablePath + ") Demanded"); new FileIOPermission(FileIOPermissionAccess.PathDiscovery, executablePath).Demand(); } return executablePath; } } ////// Gets the /// path for the executable file that started the application. /// ////// /// public static string LocalUserAppDataPath { // NOTE : Don't obsolete these. GetDataPath isn't on SystemInformation, and it // : provides the Win2K logo required adornments to the directory (Company\Product\Version) // get { try { if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed) { string data = AppDomain.CurrentDomain.GetData(CLICKONCE_APPS_DATADIRECTORY) as string; if (data != null) { return data; } } } catch (Exception ex) { if (ClientUtils.IsSecurityOrCriticalException(ex)) { throw; } } return GetDataPath(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)); } } ///Gets the path for the application data specific to a local, non-roaming user. ////// /// public static bool MessageLoop { get { return ThreadContext.FromCurrent().GetMessageLoop(); } } ////// Determines if a message loop exists on this thread. /// ////// /// public static FormCollection OpenForms { [UIPermission(SecurityAction.Demand, Window=UIPermissionWindow.AllWindows)] get { return OpenFormsInternal; } } ////// Gets the forms collection associated with this application. /// ////// internal static FormCollection OpenFormsInternal { get { if (forms == null) { forms = new FormCollection(); } return forms; } } ////// Internal version of OpenForms without the security demand. /// ////// internal static void OpenFormsInternalAdd(Form form) { OpenFormsInternal.Add(form); } ////// Thread safe addition of form to the OpenForms collection. /// ////// internal static void OpenFormsInternalRemove(Form form) { OpenFormsInternal.Remove(form); } ////// Thread safe removal of form from the OpenForms collection. /// ////// /// public static string ProductName { get { lock(internalSyncObject) { if (productName == null) { // custom attribute // Assembly entryAssembly = Assembly.GetEntryAssembly(); if (entryAssembly != null) { object[] attrs = entryAssembly.GetCustomAttributes(typeof(AssemblyProductAttribute), false); if (attrs != null && attrs.Length > 0) { productName = ((AssemblyProductAttribute)attrs[0]).Product; } } // win32 version info // if (productName == null || productName.Length == 0) { productName = GetAppFileVersionInfo().ProductName; if (productName != null) { productName = productName.Trim(); } } // fake it with namespace // won't work with MC++ see GetAppMainType. if (productName == null || productName.Length == 0) { Type t = GetAppMainType(); if (t != null) { string ns = t.Namespace; if (!string.IsNullOrEmpty(ns)) { int lastDot = ns.LastIndexOf("."); if (lastDot != -1 && lastDot < ns.Length - 1) { productName = ns.Substring(lastDot+1); } else { productName = ns; } } else{ // last ditch... use the main type // productName = t.Name; } } } } } return productName; } } ////// Gets /// the product name associated with this application. /// ////// /// public static string ProductVersion { get { lock(internalSyncObject) { if (productVersion == null) { // custom attribute // Assembly entryAssembly = Assembly.GetEntryAssembly(); if (entryAssembly != null) { object[] attrs = entryAssembly.GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false); if (attrs != null && attrs.Length > 0) { productVersion = ((AssemblyInformationalVersionAttribute)attrs[0]).InformationalVersion; } } // win32 version info // if (productVersion == null || productVersion.Length == 0) { productVersion = GetAppFileVersionInfo().ProductVersion; if (productVersion != null) { productVersion = productVersion.Trim(); } } // fake it // if (productVersion == null || productVersion.Length == 0) { productVersion = "1.0.0.0"; } } } return productVersion; } } // Allows the hosting environment to register a callback [ EditorBrowsable(EditorBrowsableState.Advanced), SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode) ] public static void RegisterMessageLoop(MessageLoopCallback callback) { ThreadContext.FromCurrent().RegisterMessageLoop(callback); } ////// Gets /// the product version associated with this application. /// ////// /// Magic property that answers a simple question - are my controls currently going to render with // visual styles? If you are doing visual styles rendering, use this to be consistent with the rest // of the controls in your app. /// public static bool RenderWithVisualStyles { get { return (ComCtlSupportsVisualStyles && VisualStyles.VisualStyleRenderer.IsSupported); } } ////// /// public static string SafeTopLevelCaptionFormat { get { if (safeTopLevelCaptionSuffix == null) { safeTopLevelCaptionSuffix = SR.GetString(SR.SafeTopLevelCaptionFormat); // 0 - original, 1 - zone, 2 - site } return safeTopLevelCaptionSuffix; } set { Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "WindowAdornmentModification Demanded"); IntSecurity.WindowAdornmentModification.Demand(); if (value == null) value = string.Empty; safeTopLevelCaptionSuffix = value; } } ///Gets or sets the format string to apply to top level window captions /// when they are displayed with a warning banner. ////// /// /// SECREVIEW ReviewImperitiveSecurity: /// vulnerability to watch out for: A method uses imperative security and might be constructing the permission using state information or return values that can change while the demand is active. /// reason for exclude: the return value of GetModuleFileName shouldnt change between when we called it and when we demanded permissions. [SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")] public static string StartupPath { get { if (startupPath == null) { StringBuilder sb = new StringBuilder(NativeMethods.MAX_PATH); UnsafeNativeMethods.GetModuleFileName(NativeMethods.NullHandleRef, sb, sb.Capacity); startupPath = Path.GetDirectoryName(sb.ToString()); } Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "FileIO(" + startupPath + ") Demanded"); new FileIOPermission(FileIOPermissionAccess.PathDiscovery, startupPath).Demand(); return startupPath; } } // Allows the hosting environment to unregister a callback [ EditorBrowsable(EditorBrowsableState.Advanced), SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode) ] public static void UnregisterMessageLoop() { ThreadContext.FromCurrent().RegisterMessageLoop(null); } ////// Gets the /// path for the executable file that started the application. /// ////// /// public static bool UseWaitCursor { get { return useWaitCursor; } set { lock (FormCollection.CollectionSyncRoot) { useWaitCursor = value; // Set the WaitCursor of all forms. foreach (Form f in OpenFormsInternal) { f.UseWaitCursor = useWaitCursor; } } } } ///Gets /// or sets whether the wait cursor is used for all open forms of the application. ////// /// public static string UserAppDataPath { // NOTE : Don't obsolete these. GetDataPath isn't on SystemInformation, and it // : provides the Win2K logo required adornments to the directory (Company\Product\Version) // get { try { if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed) { string data = AppDomain.CurrentDomain.GetData(CLICKONCE_APPS_DATADIRECTORY) as string; if (data != null) { return data; } } } catch (Exception ex) { if (ClientUtils.IsSecurityOrCriticalException(ex)) { throw; } } return GetDataPath(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)); } } ///Gets the path for the application data specific to the roaming user. ////// /// public static RegistryKey UserAppDataRegistry { get { string template = @"Software\{0}\{1}\{2}"; return Registry.CurrentUser.CreateSubKey(string.Format(CultureInfo.CurrentCulture, template, CompanyName, ProductName, ProductVersion)); } } internal static bool UseVisualStyles { get { return useVisualStyles; } } internal static string WindowsFormsVersion { get { return "WindowsForms10"; } } internal static string WindowMessagesVersion { get { return "WindowsForms12"; } } ///Gets the registry key of /// the application data specific to the roaming user. ////// /// public static VisualStyleState VisualStyleState { get { if (!VisualStyleInformation.IsSupportedByOS) { return VisualStyleState.NoneEnabled; } VisualStyleState vState = (VisualStyleState) SafeNativeMethods.GetThemeAppProperties(); return vState; } set { if (VisualStyleInformation.IsSupportedByOS) { if (!ClientUtils.IsEnumValid(value, (int)value, (int)VisualStyleState.NoneEnabled, (int)VisualStyleState.ClientAndNonClientAreasEnabled)) { throw new InvalidEnumArgumentException("value", (int)value, typeof(VisualStyleState)); } SafeNativeMethods.SetThemeAppProperties((int)value); //248887 we need to send a WM_THEMECHANGED to the top level windows of this application. //We do it this way to ensure that we get all top level windows -- whether we created them or not. SafeNativeMethods.EnumThreadWindowsCallback callback = new SafeNativeMethods.EnumThreadWindowsCallback(Application.SendThemeChanged); SafeNativeMethods.EnumWindows(callback, IntPtr.Zero); GC.KeepAlive(callback); } } } ////// Use this property to determine how visual styles will be applied to this application. /// This property is meaningful only if visual styles are supported on the current /// platform (VisualStyleInformation.SupportedByOS is true). /// /// This property can be set only to one of the S.W.F.VisualStyles.VisualStyleState enum values. /// ////// This helper broadcasts out a WM_THEMECHANGED to appropriate top level windows of this app. /// private static bool SendThemeChanged(IntPtr handle, IntPtr extraParameter) { int processId; int thisPID = SafeNativeMethods.GetCurrentProcessId(); SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(null, handle), out processId); if (processId == thisPID && SafeNativeMethods.IsWindowVisible(new HandleRef(null, handle))) { SendThemeChangedRecursive(handle, IntPtr.Zero); SafeNativeMethods.RedrawWindow(new HandleRef(null, handle), null, NativeMethods.NullHandleRef, NativeMethods.RDW_INVALIDATE | NativeMethods.RDW_FRAME | NativeMethods.RDW_ERASE | NativeMethods.RDW_ALLCHILDREN); } return true; } ////// This helper broadcasts out a WM_THEMECHANGED this window and all children. /// it is assumed at this point that the handle belongs to the current process and has a visible top level window. /// private static bool SendThemeChangedRecursive(IntPtr handle, IntPtr lparam) { //first send to all children... UnsafeNativeMethods.EnumChildWindows(new HandleRef(null, handle), new NativeMethods.EnumChildrenCallback(Application.SendThemeChangedRecursive), NativeMethods.NullHandleRef); //then do myself. UnsafeNativeMethods.SendMessage(new HandleRef(null, handle), NativeMethods.WM_THEMECHANGED, 0, 0); return true; } ////// /// public static event EventHandler ApplicationExit { add { AddEventHandler(EVENT_APPLICATIONEXIT, value); } remove { RemoveEventHandler(EVENT_APPLICATIONEXIT, value); } } private static void AddEventHandler(object key, Delegate value) { lock(internalSyncObject) { if (null == eventHandlers) { eventHandlers = new EventHandlerList(); } eventHandlers.AddHandler(key, value); } } private static void RemoveEventHandler(object key, Delegate value) { lock(internalSyncObject) { if (null == eventHandlers) { return; } eventHandlers.RemoveHandler(key, value); } } ///Occurs when the application is about to shut down. ////// /// public static void AddMessageFilter(IMessageFilter value) { Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "ManipulateWndProcAndHandles Demanded"); IntSecurity.UnmanagedCode.Demand(); ThreadContext.FromCurrent().AddMessageFilter(value); } ///Adds a message filter to monitor Windows messages as they are routed to their /// destinations. ////// Processes all message filters for given message /// [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode), EditorBrowsable(EditorBrowsableState.Advanced), SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference") // using ref is OK. ] public static bool FilterMessage(ref Message message) { bool modified; // Create copy of MSG structure NativeMethods.MSG msg = new NativeMethods.MSG(); msg.hwnd = message.HWnd; msg.message = message.Msg; msg.wParam = message.WParam; msg.lParam = message.LParam; bool processed = ThreadContext.FromCurrent().ProcessFilters(ref msg, out modified); if (modified) { message.HWnd = msg.hwnd; message.Msg = msg.message; message.WParam = msg.wParam; message.LParam = msg.lParam; } return processed; } ////// /// public static event EventHandler Idle { add { ThreadContext current = ThreadContext.FromCurrent(); lock(current) { current.idleHandler += value; // This just ensures that the component manager is hooked up. We // need it for idle time processing. // object o = current.ComponentManager; } } remove { ThreadContext current = ThreadContext.FromCurrent(); lock(current) { current.idleHandler -= value; } } } ////// Occurs when the application has finished processing and is about to enter the /// idle state. /// ////// /// [EditorBrowsable(EditorBrowsableState.Advanced)] public static event EventHandler EnterThreadModal { [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] add { ThreadContext current = ThreadContext.FromCurrent(); lock(current) { current.enterModalHandler += value; } } [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] remove { ThreadContext current = ThreadContext.FromCurrent(); lock(current) { current.enterModalHandler -= value; } } } ////// Occurs when the application is about to enter a modal state /// ////// /// [EditorBrowsable(EditorBrowsableState.Advanced)] public static event EventHandler LeaveThreadModal { [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] add { ThreadContext current = ThreadContext.FromCurrent(); lock(current) { current.leaveModalHandler += value; } } [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] remove { ThreadContext current = ThreadContext.FromCurrent(); lock(current) { current.leaveModalHandler -= value; } } } ////// Occurs when the application is about to leave a modal state /// ////// /// public static event ThreadExceptionEventHandler ThreadException { add { Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "AffectThreadBehavior Demanded"); IntSecurity.AffectThreadBehavior.Demand(); ThreadContext current = ThreadContext.FromCurrent(); lock(current) { current.threadExceptionHandler = value; } } remove { ThreadContext current = ThreadContext.FromCurrent(); lock(current) { current.threadExceptionHandler -= value; } } } ///Occurs when an untrapped thread exception is thrown. ////// /// public static event EventHandler ThreadExit { add { AddEventHandler(EVENT_THREADEXIT, value); } remove { RemoveEventHandler(EVENT_THREADEXIT, value); } } ///Occurs when a thread is about to shut down. When /// the main thread for an application is about to be shut down, /// this event will be raised first, followed by an ApplicationExit /// event. ////// /// Called immediately before we begin pumping messages for a modal message loop. /// Does not actually start a message pump; that's the caller's responsibility. /// ///internal static void BeginModalMessageLoop() { ThreadContext.FromCurrent().BeginModalMessageLoop(null); } /// /// /// public static void DoEvents() { ThreadContext.FromCurrent().RunMessageLoop(NativeMethods.MSOCM.msoloopDoEvents, null); } ///Processes /// all Windows messages currently in the message queue. ////// internal static void DoEventsModal() { ThreadContext.FromCurrent().RunMessageLoop(NativeMethods.MSOCM.msoloopDoEventsModal, null); } ////// /// public static void EnableVisualStyles() { string assemblyLoc = null; // SECREVIEW : This Assert is ok, getting the module path is a safe operation, // the result is provided by the system. // FileIOPermission fiop = new FileIOPermission(PermissionState.None); fiop.AllFiles = FileIOPermissionAccess.PathDiscovery; fiop.Assert(); try { assemblyLoc = typeof(Application).Assembly.Location; } finally { CodeAccessPermission.RevertAssert(); } // Pull manifest from our resources if (assemblyLoc != null) { EnableVisualStylesInternal(assemblyLoc, 101); } } ////// Enables visual styles for all subsequent Application.Run() and CreateHandle() calls. /// Uses the default theming manifest file shipped with the redist. /// ////// Internal version ***WITHOUT SECURITY DEMAND***. /// private static void EnableVisualStylesInternal(string assemblyFileName, int nativeResourceID) { //Note that if the following call fails, we don't throw an exception. //Theming scope won't work, thats all. useVisualStyles = UnsafeNativeMethods.ThemingScope.CreateActivationContext(assemblyFileName, nativeResourceID); } ////// /// Called immediately after we stop pumping messages for a modal message loop. /// Does not actually end the message pump itself. /// ///internal static void EndModalMessageLoop() { ThreadContext.FromCurrent().EndModalMessageLoop(null); } /// /// /// public static void Exit() { Exit(null); } ///Overload of Exit that does not care about e.Cancel. ////// /// [ EditorBrowsable(EditorBrowsableState.Advanced), SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers") ] public static void Exit(CancelEventArgs e) { Assembly entryAssembly = Assembly.GetEntryAssembly(); Assembly callingAssembly = Assembly.GetCallingAssembly(); if (entryAssembly == null || callingAssembly == null || !entryAssembly.Equals(callingAssembly)) { Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "AffectThreadBehavior Demanded"); IntSecurity.AffectThreadBehavior.Demand(); } bool cancelExit = ExitInternal(); if (e != null) { e.Cancel = cancelExit; } } ///Informs all message pumps that they are to terminate and /// then closes all application windows after the messages have been processed. /// e.Cancel indicates whether any of the open forms cancelled the exit call. ////// private static bool ExitInternal() { bool cancelExit = false; lock (internalSyncObject) { if (exiting) { return false; } exiting = true; try { // Raise the FormClosing and FormClosed events for each open form if (forms != null) { foreach (Form f in OpenFormsInternal) { if (f.RaiseFormClosingOnAppExit()) { cancelExit = true; break; // quit the loop as soon as one form refuses to close } } } if (!cancelExit) { if (forms != null) { while (OpenFormsInternal.Count > 0) { OpenFormsInternal[0].RaiseFormClosedOnAppExit(); // OnFormClosed removes the form from the FormCollection } } ThreadContext.ExitApplication(); } } finally { exiting = false; } } return cancelExit; } ///Private version of Exit which does not do any security checks. ////// /// public static void ExitThread() { Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "AffectThreadBehavior Demanded"); IntSecurity.AffectThreadBehavior.Demand(); ExitThreadInternal(); } private static void ExitThreadInternal() { ThreadContext context = ThreadContext.FromCurrent(); if (context.ApplicationContext != null) { context.ApplicationContext.ExitThread(); } else { context.Dispose(true); } } // When a Form receives a WM_ACTIVATE message, it calls this method so we can do the // appropriate MsoComponentManager activation magic internal static void FormActivated(bool modal, bool activated) { if (modal) { return; } ThreadContext.FromCurrent().FormActivated(activated); } ///Exits the message loop on the /// current thread and closes all windows on the thread. ////// /// Retrieves the FileVersionInfo associated with the main module for /// the application. /// private static FileVersionInfo GetAppFileVersionInfo() { lock (internalSyncObject) { if (appFileVersion == null) { Type t = GetAppMainType(); if (t != null) { // SECREVIEW : This Assert is ok, getting the module's version is a safe operation, // the result is provided by the system. // FileIOPermission fiop = new FileIOPermission( PermissionState.None ); fiop.AllFiles = FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read; fiop.Assert(); try { appFileVersion = FileVersionInfo.GetVersionInfo(t.Module.FullyQualifiedName); } finally { CodeAccessPermission.RevertAssert(); } } else { appFileVersion = FileVersionInfo.GetVersionInfo(ExecutablePath); } } } return(FileVersionInfo)appFileVersion; } ////// /// Retrieves the Type that contains the "Main" method. /// private static Type GetAppMainType() { lock(internalSyncObject) { if (mainType == null) { Assembly exe = Assembly.GetEntryAssembly(); // Get Main type...This doesn't work in MC++ because Main is a global function and not // a class static method (it doesn't belong to a Type). if (exe != null) { mainType = exe.EntryPoint.ReflectedType; } } } return mainType; } ////// Locates a thread context given a window handle. /// private static ThreadContext GetContextForHandle(HandleRef handle) { int pid; int id = SafeNativeMethods.GetWindowThreadProcessId(handle, out pid); ThreadContext cxt = ThreadContext.FromId(id); Debug.Assert(cxt != null, "No thread context for handle. This is expected if you saw a previous assert about the handle being invalid."); return cxt; } ////// /// Returns a string that is the combination of the /// basePath + CompanyName + ProducName + ProductVersion. This /// will also create the directory if it doesn't exist. /// private static string GetDataPath(String basePath) { string template = @"{0}\{1}\{2}\{3}"; string company = CompanyName; string product = ProductName; string version = ProductVersion; string path = string.Format(CultureInfo.CurrentCulture, template, new object[] {basePath, company, product, version}); lock(internalSyncObject) { if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } } return path; } ////// /// Called by the last thread context before it shuts down. /// private static void RaiseExit() { if (eventHandlers != null) { Delegate exit = eventHandlers[EVENT_APPLICATIONEXIT]; if (exit != null) ((EventHandler)exit)(null, EventArgs.Empty); } } ////// /// Called by the each thread context before it shuts down. /// private static void RaiseThreadExit() { if (eventHandlers != null) { Delegate exit = eventHandlers[EVENT_THREADEXIT]; if (exit != null) { ((EventHandler)exit)(null, EventArgs.Empty); } } } ////// /// /// "Parks" the given HWND to a temporary HWND. This allows WS_CHILD windows to /// be parked. /// internal static void ParkHandle(HandleRef handle) { Debug.Assert(UnsafeNativeMethods.IsWindow(handle), "Handle being parked is not a valid window handle"); Debug.Assert(((int)UnsafeNativeMethods.GetWindowLong(handle, NativeMethods.GWL_STYLE) & NativeMethods.WS_CHILD) != 0, "Only WS_CHILD windows should be parked."); ThreadContext cxt = GetContextForHandle(handle); if (cxt != null) { cxt.ParkingWindow.ParkHandle(handle); } } ////// /// /// "Parks" the given HWND to a temporary HWND. This allows WS_CHILD windows to /// be parked. /// internal static void ParkHandle(CreateParams cp) { ThreadContext cxt = ThreadContext.FromCurrent(); if (cxt != null) { cp.Parent = cxt.ParkingWindow.Handle; } } ////// /// public static System.Threading.ApartmentState OleRequired() { return ThreadContext.FromCurrent().OleRequired(); } ////// Initializes OLE on the current thread. /// ////// /// public static void OnThreadException(Exception t) { ThreadContext.FromCurrent().OnThreadException(t); } ///Raises the ///event. /// /// /// "Unparks" the given HWND to a temporary HWND. This allows WS_CHILD windows to /// be parked. /// internal static void UnparkHandle(HandleRef handle) { ThreadContext cxt = GetContextForHandle(handle); if (cxt != null) { cxt.ParkingWindow.UnparkHandle(handle); } } ////// /// Raises the Idle event. /// [ EditorBrowsable(EditorBrowsableState.Advanced), SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode), SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers"), SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate") ] public static void RaiseIdle(EventArgs e) { ThreadContext current = ThreadContext.FromCurrent(); if (current.idleHandler != null) { current.idleHandler(Thread.CurrentThread, e); } } ////// /// public static void RemoveMessageFilter(IMessageFilter value) { ThreadContext.FromCurrent().RemoveMessageFilter(value); } ///Removes a message /// filter from the application's message pump. ////// /// [ SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode), SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode) ] public static void Restart() { if (Assembly.GetEntryAssembly() == null) { throw new NotSupportedException(SR.GetString(SR.RestartNotSupported)); } bool hrefExeCase = false; Process process = Process.GetCurrentProcess(); Debug.Assert(process != null); if (String.Equals(process.MainModule.ModuleName, IEEXEC, StringComparison.OrdinalIgnoreCase)) { string clrPath = string.Empty; // SECREVIEW : This Assert is ok, getting the module path is a safe operation, // the result is provided by the system. // new FileIOPermission(PermissionState.Unrestricted).Assert(); try { clrPath = Path.GetDirectoryName(typeof(object).Module.FullyQualifiedName); } finally { CodeAccessPermission.RevertAssert(); } if (String.Equals(clrPath + "\\" + IEEXEC, process.MainModule.FileName, StringComparison.OrdinalIgnoreCase)) { // HRef exe case hrefExeCase = true; ExitInternal(); string launchUrl = AppDomain.CurrentDomain.GetData("APP_LAUNCH_URL") as string; if (launchUrl != null) { Process.Start(process.MainModule.FileName, launchUrl); } } } if (!hrefExeCase) { if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed) { // ClickOnce app case string appFullName = System.Deployment.Application.ApplicationDeployment.CurrentDeployment.UpdatedApplicationFullName; UInt32 hostType = (UInt32) Application.ClickOnceUtility.GetHostTypeFromMetaData(appFullName); ExitInternal(); UnsafeNativeMethods.CorLaunchApplication(hostType, appFullName, 0, null, 0, null, new UnsafeNativeMethods.PROCESS_INFORMATION()); } else { // Regular app case String[] arguments = Environment.GetCommandLineArgs(); Debug.Assert(arguments != null && arguments.Length > 0); StringBuilder sb = new StringBuilder((arguments.Length - 1) * 16); for (int argumentIndex = 1; argumentIndex < arguments.Length - 1; argumentIndex++) { sb.Append('"'); sb.Append(arguments[argumentIndex]); sb.Append("\" "); } if (arguments.Length > 1) { sb.Append('"'); sb.Append(arguments[arguments.Length - 1]); sb.Append('"'); } ProcessStartInfo currentStartInfo = Process.GetCurrentProcess().StartInfo; currentStartInfo.FileName = Application.ExecutablePath; // [....]: use this according to spec. // String executable = Assembly.GetEntryAssembly().CodeBase; // Debug.Assert(executable != null); if (sb.Length > 0) { currentStartInfo.Arguments = sb.ToString(); } ExitInternal(); Process.Start(currentStartInfo); } } } ///Restarts the application. ////// /// public static void Run() { ThreadContext.FromCurrent().RunMessageLoop(NativeMethods.MSOCM.msoloopMain, new ApplicationContext()); } ///Begins running a /// standard /// application message loop on the current thread, /// without a form. ////// /// public static void Run(Form mainForm) { ThreadContext.FromCurrent().RunMessageLoop(NativeMethods.MSOCM.msoloopMain, new ApplicationContext(mainForm)); } ///Begins running a standard application message loop on the current /// thread, and makes the specified form visible. ////// /// public static void Run(ApplicationContext context) { ThreadContext.FromCurrent().RunMessageLoop(NativeMethods.MSOCM.msoloopMain, context); } ///Begins running a /// standard /// application message loop on the current thread, /// without a form. ////// /// Runs a modal dialog. This starts a special type of message loop that runs until /// the dialog has a valid DialogResult. This is called internally by a form /// when an application calls System.Windows.Forms.Form.ShowDialog(). /// ///internal static void RunDialog(Form form) { ThreadContext.FromCurrent().RunMessageLoop(NativeMethods.MSOCM.msoloopModalForm, new ModalApplicationContext(form)); } /// /// /// Sets the static UseCompatibleTextRenderingDefault field on Control to the value passed in. /// This switch determines the default text rendering engine to use by some controls that support /// switching rendering engine. /// [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] public static void SetCompatibleTextRenderingDefault(bool defaultValue) { if (NativeWindow.AnyHandleCreated) { throw new InvalidOperationException(SR.GetString(SR.Win32WindowAlreadyCreated)); } Control.UseCompatibleTextRenderingDefault = defaultValue; } ////// /// Sets the suspend/hibernate state of the machine. /// Returns true if the call succeeded, else false. /// public static bool SetSuspendState(PowerState state, bool force, bool disableWakeEvent) { IntSecurity.AffectMachineState.Demand(); return UnsafeNativeMethods.SetSuspendState(state == PowerState.Hibernate, force, disableWakeEvent); } ////// Overload version of SetUnhandledExceptionMode that sets the UnhandledExceptionMode /// mode at the current thread level. /// public static void SetUnhandledExceptionMode(UnhandledExceptionMode mode) { SetUnhandledExceptionMode(mode, true /*threadScope*/); } ////// This method can be used to modify the exception handling behavior of /// NativeWindow. By default, NativeWindow will detect if an application /// is running under a debugger, or is running on a machine with a debugger /// installed. In this case, an unhandled exception in the NativeWindow's /// WndProc method will remain unhandled so the debugger can trap it. If /// there is no debugger installed NativeWindow will trap the exception /// and route it to the Application class's unhandled exception filter. /// /// You can control this behavior via a config file, or directly through /// code using this method. Setting the unhandled exception mode does /// not change the behavior of any NativeWindow objects that are currently /// connected to window handles; it only affects new handle connections. /// /// The parameter threadScope defines the scope of the setting: either /// the current thread or the application. /// When a thread exception mode isn't UnhandledExceptionMode.Automatic, it takes /// precedence over the application exception mode. /// public static void SetUnhandledExceptionMode(UnhandledExceptionMode mode, bool threadScope) { Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "AffectThreadBehavior Demanded"); IntSecurity.AffectThreadBehavior.Demand(); NativeWindow.SetUnhandledExceptionModeInternal(mode, threadScope); } // Exposes GetHostTypeFromMetaData provided by the ClickOnce team. // Used to restart ClickOnce applications in Application.Restart(). private class ClickOnceUtility { public enum HostType { Default = 0x0, AppLaunch = 0x1, CorFlag = 0x2 } private ClickOnceUtility() { } public static HostType GetHostTypeFromMetaData(string appFullName) { HostType ht = HostType.Default; try { // Convert into IDefinitionAppId. IDefinitionAppId defAppId = IsolationInterop.AppIdAuthority.TextToDefinition(0, appFullName); bool isFullTrust = GetPropertyBoolean(defAppId, "IsFullTrust"); ht = isFullTrust ? HostType.CorFlag : HostType.AppLaunch; } catch { // Eating exceptions. IsFullTrust metadata is not present. } return ht; } // Get metadata property as boolean. private static bool GetPropertyBoolean(IDefinitionAppId appId, string propName) { string boolStr = GetPropertyString(appId, propName); if (string.IsNullOrEmpty(boolStr)) { return false; } try { return Convert.ToBoolean(boolStr, CultureInfo.InvariantCulture); } catch { return false; } } // Get metadata property as string. private static string GetPropertyString(IDefinitionAppId appId, string propName) { // Retrieve property and convert to string. byte[] bytes = IsolationInterop.UserStore.GetDeploymentProperty(0, appId, InstallReference, new Guid("2ad613da-6fdb-4671-af9e-18ab2e4df4d8"), propName); // Check for valid Unicode string. Must end with L'\0'. int length = bytes.Length; if ((length == 0) || ((bytes.Length % 2) != 0) || (bytes[length - 2] != 0) || (bytes[length - 1] != 0)) { return null; } return Encoding.Unicode.GetString(bytes, 0, length - 2); } // Get the ClickOnce-specific constant install reference. private static StoreApplicationReference InstallReference { get { return new StoreApplicationReference( IsolationInterop.GUID_SXS_INSTALL_REFERENCE_SCHEME_OPAQUESTRING, "{3f471841-eef2-47d6-89c0-d028f03a4ad5}", null); } } } ////// /// This is our implementation of the MSO ComponentManager. The Componoent Manager is /// an object that is responsible for handling all message loop activity in a process. /// The idea is that someone in the process implements the component manager and then /// anyone who wants access to the message loop can get to it. We implement this /// so we have good interop with office and VS. The first time we need a /// component manager, we search the OLE message filter for one. If that fails, we /// create our own and install it in the message filter. /// /// This class is not used when running inside the Visual Studio shell. /// private class ComponentManager : UnsafeNativeMethods.IMsoComponentManager { // ComponentManager instance data. // private class ComponentHashtableEntry { public UnsafeNativeMethods.IMsoComponent component; public NativeMethods.MSOCRINFOSTRUCT componentInfo; } private Hashtable oleComponents; private int cookieCounter = 0; private UnsafeNativeMethods.IMsoComponent activeComponent = null; private UnsafeNativeMethods.IMsoComponent trackingComponent = null; private int currentState = 0; private Hashtable OleComponents { get { if (oleComponents == null) { oleComponents = new Hashtable(); cookieCounter = 0; } return oleComponents; } } ////// /// Return in *ppvObj an implementation of interface iid for service /// guidService (same as IServiceProvider::QueryService). /// Return NOERROR if the requested service is supported, otherwise return /// NULL in *ppvObj and an appropriate error (eg E_FAIL, E_NOINTERFACE). /// int UnsafeNativeMethods.IMsoComponentManager.QueryService( ref Guid guidService, ref Guid iid, out object ppvObj) { ppvObj = null; return NativeMethods.E_NOINTERFACE; } ////// /// Standard FDebugMessage method. /// Since IMsoComponentManager is a reference counted interface, /// MsoDWGetChkMemCounter should be used when processing the /// msodmWriteBe message. /// bool UnsafeNativeMethods.IMsoComponentManager.FDebugMessage( IntPtr hInst, int msg, IntPtr wparam, IntPtr lparam) { return true; } ////// /// Register component piComponent and its registration info pcrinfo with /// this component manager. Return in *pdwComponentID a cookie which will /// identify the component when it calls other IMsoComponentManager /// methods. /// Return TRUE if successful, FALSE otherwise. /// bool UnsafeNativeMethods.IMsoComponentManager.FRegisterComponent(UnsafeNativeMethods.IMsoComponent component, NativeMethods.MSOCRINFOSTRUCT pcrinfo, out int dwComponentID) { // Construct Hashtable entry for this component // ComponentHashtableEntry entry = new ComponentHashtableEntry(); entry.component = component; entry.componentInfo = pcrinfo; OleComponents.Add(++cookieCounter, entry); // Return the cookie // dwComponentID = cookieCounter; Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager: Component registered. ID: " + cookieCounter.ToString(CultureInfo.InvariantCulture)); return true; } ////// /// Undo the registration of the component identified by dwComponentID /// (the cookie returned from the FRegisterComponent method). /// Return TRUE if successful, FALSE otherwise. /// bool UnsafeNativeMethods.IMsoComponentManager.FRevokeComponent(int dwComponentID) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager: Revoking component " + dwComponentID.ToString(CultureInfo.InvariantCulture)); ComponentHashtableEntry entry = (ComponentHashtableEntry)OleComponents[dwComponentID]; if (entry == null) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "Compoenent not registered."); return false; } if (entry.component == activeComponent) { activeComponent = null; } if (entry.component == trackingComponent) { trackingComponent = null; } OleComponents.Remove(dwComponentID); return true; } ////// /// Update the registration info of the component identified by /// dwComponentID (the cookie returned from FRegisterComponent) with the /// new registration information pcrinfo. /// Typically this is used to update the idle time registration data, but /// can be used to update other registration data as well. /// Return TRUE if successful, FALSE otherwise. /// bool UnsafeNativeMethods.IMsoComponentManager.FUpdateComponentRegistration( int dwComponentID, NativeMethods.MSOCRINFOSTRUCT info ) { // Update the registration info // ComponentHashtableEntry entry = (ComponentHashtableEntry)OleComponents[dwComponentID]; if (entry == null) { return false; } entry.componentInfo = info; return true; } ////// /// Notify component manager that component identified by dwComponentID /// (cookie returned from FRegisterComponent) has been activated. /// The active component gets the chance to process messages before they /// are dispatched (via IMsoComponent::FPreTranslateMessage) and typically /// gets first chance at idle time after the host. /// This method fails if another component is already Exclusively Active. /// In this case, FALSE is returned and SetLastError is set to /// msoerrACompIsXActive (comp usually need not take any special action /// in this case). /// Return TRUE if successful. /// bool UnsafeNativeMethods.IMsoComponentManager.FOnComponentActivate(int dwComponentID) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager: Component activated. ID: " + dwComponentID.ToString(CultureInfo.InvariantCulture)); ComponentHashtableEntry entry = (ComponentHashtableEntry)OleComponents[dwComponentID]; if (entry == null) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "*** Component not registered ***"); return false; } Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "New active component is : " + entry.component.ToString()); activeComponent = entry.component; return true; } ////// /// Called to inform component manager that component identified by /// dwComponentID (cookie returned from FRegisterComponent) wishes /// to perform a tracking operation (such as mouse tracking). /// The component calls this method with fTrack == TRUE to begin the /// tracking operation and with fTrack == FALSE to end the operation. /// During the tracking operation the component manager routes messages /// to the tracking component (via IMsoComponent::FPreTranslateMessage) /// rather than to the active component. When the tracking operation ends, /// the component manager should resume routing messages to the active /// component. /// Note: component manager should perform no idle time processing during a /// tracking operation other than give the tracking component idle /// time via IMsoComponent::FDoIdle. /// Note: there can only be one tracking component at a time. /// Return TRUE if successful, FALSE otherwise. /// bool UnsafeNativeMethods.IMsoComponentManager.FSetTrackingComponent(int dwComponentID, bool fTrack) { ComponentHashtableEntry entry = (ComponentHashtableEntry)OleComponents[dwComponentID]; if (entry == null) { return false; } if (entry.component == trackingComponent ^ fTrack) { return false; } if (fTrack) { trackingComponent = entry.component; } else { trackingComponent = null; } return true; } ////// /// Notify component manager that component identified by dwComponentID /// (cookie returned from FRegisterComponent) is entering the state /// identified by uStateID (msocstateXXX value). (For convenience when /// dealing with sub CompMgrs, the host can call this method passing 0 for /// dwComponentID.) /// Component manager should notify all other interested components within /// the state context indicated by uContext (a msoccontextXXX value), /// excluding those within the state context of a CompMgr in rgpicmExclude, /// via IMsoComponent::OnEnterState (see "Comments on State Contexts", /// above). /// Component Manager should also take appropriate action depending on the /// value of uStateID (see msocstate comments, above). /// dwReserved is reserved for future use and should be zero. /// /// rgpicmExclude (can be NULL) is an array of cpicmExclude CompMgrs (can /// include root CompMgr and/or sub CompMgrs); components within the state /// context of a CompMgr appearing in this array should NOT be notified of /// the state change (note: if uContext is msoccontextMine, the only /// CompMgrs in rgpicmExclude that are checked for exclusion are those that /// are sub CompMgrs of this Component Manager, since all other CompMgrs /// are outside of this Component Manager's state context anyway.) /// /// Note: Calls to this method are symmetric with calls to /// FOnComponentExitState. /// That is, if n OnComponentEnterState calls are made, the component is /// considered to be in the state until n FOnComponentExitState calls are /// made. Before revoking its registration a component must make a /// sufficient number of FOnComponentExitState calls to offset any /// outstanding OnComponentEnterState calls it has made. /// /// Note: inplace objects should not call this method with /// uStateID == msocstateModal when entering modal state. Such objects /// should call IOleInPlaceFrame::EnableModeless instead. /// void UnsafeNativeMethods.IMsoComponentManager.OnComponentEnterState( int dwComponentID, int uStateID, int uContext, int cpicmExclude, int rgpicmExclude, // IMsoComponentManger** int dwReserved) { currentState |= uStateID; Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager: Component enter state. ID: " + dwComponentID.ToString(CultureInfo.InvariantCulture) + " state: " + uStateID.ToString(CultureInfo.InvariantCulture)); if (uContext == NativeMethods.MSOCM.msoccontextAll || uContext == NativeMethods.MSOCM.msoccontextMine) { Debug.Indent(); // We should notify all components we contain that the state has changed. // foreach (ComponentHashtableEntry entry in OleComponents.Values) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "Notifying " + entry.component.ToString()); entry.component.OnEnterState(uStateID, true); } Debug.Unindent(); } } ////// /// Notify component manager that component identified by dwComponentID /// (cookie returned from FRegisterComponent) is exiting the state /// identified by uStateID (a msocstateXXX value). (For convenience when /// dealing with sub CompMgrs, the host can call this method passing 0 for /// dwComponentID.) /// uContext, cpicmExclude, and rgpicmExclude are as they are in /// OnComponentEnterState. /// Component manager should notify all appropriate interested components /// (taking into account uContext, cpicmExclude, rgpicmExclude) via /// IMsoComponent::OnEnterState (see "Comments on State Contexts", above). /// Component Manager should also take appropriate action depending on /// the value of uStateID (see msocstate comments, above). /// Return TRUE if, at the end of this call, the state is still in effect /// at the root of this component manager's state context /// (because the host or some other component is still in the state), /// otherwise return FALSE (ie. return what FInState would return). /// Caller can normally ignore the return value. /// /// Note: n calls to this method are symmetric with n calls to /// OnComponentEnterState (see OnComponentEnterState comments, above). /// bool UnsafeNativeMethods.IMsoComponentManager.FOnComponentExitState( int dwComponentID, int uStateID, int uContext, int cpicmExclude, int rgpicmExclude // IMsoComponentManager** ) { currentState &= ~uStateID; Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager: Component exit state. ID: " + dwComponentID.ToString(CultureInfo.InvariantCulture) + " state: " + uStateID.ToString(CultureInfo.InvariantCulture)); if (uContext == NativeMethods.MSOCM.msoccontextAll || uContext == NativeMethods.MSOCM.msoccontextMine) { Debug.Indent(); // We should notify all components we contain that the state has changed. // foreach (ComponentHashtableEntry entry in OleComponents.Values) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "Notifying " + entry.component.ToString()); entry.component.OnEnterState(uStateID, false); } Debug.Unindent(); } return false; } ////// /// Return TRUE if the state identified by uStateID (a msocstateXXX value) /// is in effect at the root of this component manager's state context, /// FALSE otherwise (see "Comments on State Contexts", above). /// pvoid is reserved for future use and should be NULL. /// bool UnsafeNativeMethods.IMsoComponentManager.FInState(int uStateID, IntPtr pvoid) { return(currentState & uStateID) != 0; } ////// /// Called periodically by a component during IMsoComponent::FDoIdle. /// Return TRUE if component can continue its idle time processing, /// FALSE if not (in which case component returns from FDoIdle.) /// bool UnsafeNativeMethods.IMsoComponentManager.FContinueIdle() { // Essentially, if we have a message on queue, then don't continue // idle processing. // NativeMethods.MSG msg = new NativeMethods.MSG(); return !UnsafeNativeMethods.PeekMessage(ref msg, NativeMethods.NullHandleRef, 0, 0, NativeMethods.PM_NOREMOVE); } ////// /// Component identified by dwComponentID (cookie returned from /// FRegisterComponent) wishes to push a message loop for reason uReason. /// uReason is one the values from the msoloop enumeration (above). /// pvLoopData is data private to the component. /// The component manager should push its message loop, /// calling IMsoComponent::FContinueMessageLoop(uReason, pvLoopData) /// during each loop iteration (see IMsoComponent::FContinueMessageLoop /// comments). When IMsoComponent::FContinueMessageLoop returns FALSE, the /// component manager terminates the loop. /// Returns TRUE if component manager terminates loop because component /// told it to (by returning FALSE from IMsoComponent::FContinueMessageLoop), /// FALSE if it had to terminate the loop for some other reason. In the /// latter case, component should perform any necessary action (such as /// cleanup). /// bool UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop( int dwComponentID, int reason, int pvLoopData // PVOID ) { // Hold onto old state to allow restore before we exit... // int currentLoopState = currentState; bool continueLoop = true; if (!OleComponents.ContainsKey(dwComponentID)) { return false; } UnsafeNativeMethods.IMsoComponent prevActive = this.activeComponent; try { // Execute the message loop until the active component tells us to stop. // NativeMethods.MSG msg = new NativeMethods.MSG(); NativeMethods.MSG[] rgmsg = new NativeMethods.MSG[] {msg}; bool unicodeWindow = false; UnsafeNativeMethods.IMsoComponent requestingComponent; ComponentHashtableEntry entry = (ComponentHashtableEntry)OleComponents[dwComponentID]; if (entry == null) { return false; } requestingComponent = entry.component; this.activeComponent = requestingComponent; Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : Pushing message loop " + reason.ToString(CultureInfo.InvariantCulture)); Debug.Indent(); while (continueLoop) { // Determine the component to route the message to // UnsafeNativeMethods.IMsoComponent component; if (trackingComponent != null) { component = trackingComponent; } else if (activeComponent != null) { component = activeComponent; } else { component = requestingComponent; } bool peeked = UnsafeNativeMethods.PeekMessage(ref msg, NativeMethods.NullHandleRef, 0, 0, NativeMethods.PM_NOREMOVE); if (peeked) { rgmsg[0] = msg; continueLoop = component.FContinueMessageLoop(reason, pvLoopData, rgmsg); // If the component wants us to process the message, do it. // The component manager hosts windows from many places. We must be sensitive // to ansi / Unicode windows here. // if (continueLoop) { if (msg.hwnd != IntPtr.Zero && SafeNativeMethods.IsWindowUnicode(new HandleRef(null, msg.hwnd))) { unicodeWindow = true; UnsafeNativeMethods.GetMessageW(ref msg, NativeMethods.NullHandleRef, 0, 0); } else { unicodeWindow = false; UnsafeNativeMethods.GetMessageA(ref msg, NativeMethods.NullHandleRef, 0, 0); } if (msg.message == NativeMethods.WM_QUIT) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : Normal message loop termination"); Application.ThreadContext.FromCurrent().DisposeThreadWindows(); if (reason != NativeMethods.MSOCM.msoloopMain) { UnsafeNativeMethods.PostQuitMessage((int)msg.wParam); } continueLoop = false; break; } // Now translate and dispatch the message. // // Reading through the rather sparse documentation, // it seems we should only call FPreTranslateMessage // on the active component. But frankly, I'm afraid of what that might break. // See ASURT 29415 for more background. if (!component.FPreTranslateMessage(ref msg)) { UnsafeNativeMethods.TranslateMessage(ref msg); if (unicodeWindow) { UnsafeNativeMethods.DispatchMessageW(ref msg); } else { UnsafeNativeMethods.DispatchMessageA(ref msg); } } } } else { // If this is a DoEvents loop, then get out. There's nothing left // for us to do. // if (reason == NativeMethods.MSOCM.msoloopDoEvents || reason == NativeMethods.MSOCM.msoloopDoEventsModal) { break; } // Nothing is on the message queue. Perform idle processing // and then do a WaitMessage. // bool continueIdle = false; if (OleComponents != null) { IEnumerator enumerator = OleComponents.Values.GetEnumerator(); while (enumerator.MoveNext()) { ComponentHashtableEntry idleEntry = (ComponentHashtableEntry)enumerator.Current; continueIdle |= idleEntry.component.FDoIdle(-1); } } // give the component one more chance to terminate the // message loop. // continueLoop = component.FContinueMessageLoop(reason, pvLoopData, null); if (continueLoop) { if (continueIdle) { // If someone has asked for idle time, give it to them. However, // don't cycle immediately; wait up to 100ms. Why? Because we don't // want someone to attach to idle, forget to detach, and then ---- // the CPU. For Windows Forms this generally isn't an issue because // our component always returns false from its idle request UnsafeNativeMethods.MsgWaitForMultipleObjectsEx(0, IntPtr.Zero, 100, NativeMethods.QS_ALLINPUT, NativeMethods.MWMO_INPUTAVAILABLE); } else { // We should call GetMessage here, but we cannot because // the component manager requires that we notify the // active component before we pull the message off the // queue. This is a bit of a problem, because WaitMessage // waits for a NEW message to appear on the queue. If a // message appeared between processing and now WaitMessage // would wait for the next message. We minimize this here // by calling PeekMessage. // if (!UnsafeNativeMethods.PeekMessage(ref msg, NativeMethods.NullHandleRef, 0, 0, NativeMethods.PM_NOREMOVE)) { UnsafeNativeMethods.WaitMessage(); } } } } } Debug.Unindent(); Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : message loop " + reason.ToString(CultureInfo.InvariantCulture) + " complete."); } finally { currentState = currentLoopState; this.activeComponent = prevActive; } return !continueLoop; } ////// /// Cause the component manager to create a "sub" component manager, which /// will be one of its children in the hierarchical tree of component /// managers used to maintiain state contexts (see "Comments on State /// Contexts", above). /// piunkOuter is the controlling unknown (can be NULL), riid is the /// desired IID, and *ppvObj returns the created sub component manager. /// piunkServProv (can be NULL) is a ptr to an object supporting /// IServiceProvider interface to which the created sub component manager /// will delegate its IMsoComponentManager::QueryService calls. /// (see objext.h or docobj.h for definition of IServiceProvider). /// Returns TRUE if successful. /// bool UnsafeNativeMethods.IMsoComponentManager.FCreateSubComponentManager( object punkOuter, object punkServProv, ref Guid riid, out IntPtr ppvObj) { // We do not support sub component managers. // ppvObj = IntPtr.Zero; return false; } ////// /// Return in *ppicm an AddRef'ed ptr to this component manager's parent /// in the hierarchical tree of component managers used to maintain state /// contexts (see "Comments on State Contexts", above). /// Returns TRUE if the parent is returned, FALSE if no parent exists or /// some error occurred. /// bool UnsafeNativeMethods.IMsoComponentManager.FGetParentComponentManager(out UnsafeNativeMethods.IMsoComponentManager ppicm) { ppicm = null; return false; } ////// /// Return in *ppic an AddRef'ed ptr to the current active or tracking /// component (as indicated by dwgac (a msogacXXX value)), and /// its registration information in *pcrinfo. ppic and/or pcrinfo can be /// NULL if caller is not interested these values. If pcrinfo is not NULL, /// caller should set pcrinfo->cbSize before calling this method. /// Returns TRUE if the component indicated by dwgac exists, FALSE if no /// such component exists or some error occurred. /// dwReserved is reserved for future use and should be zero. /// bool UnsafeNativeMethods.IMsoComponentManager.FGetActiveComponent( int dwgac, UnsafeNativeMethods.IMsoComponent[] ppic, NativeMethods.MSOCRINFOSTRUCT info, int dwReserved) { UnsafeNativeMethods.IMsoComponent component = null; if (dwgac == NativeMethods.MSOCM.msogacActive) { component = activeComponent; } else if (dwgac == NativeMethods.MSOCM.msogacTracking) { component = trackingComponent; } else if (dwgac == NativeMethods.MSOCM.msogacTrackingOrActive) { if (trackingComponent != null) { component = trackingComponent; } else { component = activeComponent; } } else { Debug.Fail("Unknown dwgac in FGetActiveComponent"); } if (ppic != null) { ppic[0] = component; } if (info != null && component != null) { foreach(ComponentHashtableEntry entry in OleComponents.Values) { if (entry.component == component) { info = entry.componentInfo; break; } } } return component != null; } } ////// /// This class is the embodiment of TLS for windows forms. We do not expose this to end users because /// TLS is really just an unfortunate artifact of using Win 32. We want the world to be free /// threaded. /// ///internal sealed class ThreadContext : MarshalByRefObject, UnsafeNativeMethods.IMsoComponent { private const int STATE_OLEINITIALIZED = 0x00000001; private const int STATE_EXTERNALOLEINIT = 0x00000002; private const int STATE_INTHREADEXCEPTION = 0x00000004; private const int STATE_POSTEDQUIT = 0x00000008; private const int STATE_FILTERSNAPSHOTVALID = 0x00000010; private const int STATE_TRACKINGCOMPONENT = 0x00000020; private const int INVALID_ID = unchecked((int)0xFFFFFFFF); private static Hashtable contextHash = new Hashtable(); // When this gets to zero, we'll invoke a full garbage // collect and check for root/window leaks. // private static object tcInternalSyncObject = new object(); private static int totalMessageLoopCount; private static int baseLoopReason; [ ThreadStatic ] private static ThreadContext currentThreadContext; internal ThreadExceptionEventHandler threadExceptionHandler; internal EventHandler idleHandler; internal EventHandler enterModalHandler; internal EventHandler leaveModalHandler; private ApplicationContext applicationContext; private ParkingWindow parkingWindow; private Control marshalingControl; private CultureInfo culture; private ArrayList messageFilters; private IMessageFilter[] messageFilterSnapshot; private IntPtr handle; private int id; private int messageLoopCount; private int threadState; private int modalCount; // used for correct restoration of focus after modality private WeakReference activatingControlRef; // IMsoComponentManager stuff // private UnsafeNativeMethods.IMsoComponentManager componentManager; private bool externalComponentManager; private bool fetchingComponentManager; // IMsoComponent stuff private int componentID = INVALID_ID; private Form currentForm; private ThreadWindows threadWindows; private NativeMethods.MSG tempMsg = new NativeMethods.MSG(); private int disposeCount; // To make sure that we don't allow // reentrancy in Dispose() // Debug helper variable #if DEBUG private int debugModalCounter; #endif // Refer VSWhidbey 258748 // Refer VS Whidbey 337882 // We need to set this flag if we have started the ModalMessageLoop so that we dont create the ThreadWindows // when the ComponentManager calls on us (as IMSOComponent) during the OnEnterState. private bool ourModalLoop; // A private field on Application that stores the callback delegate private MessageLoopCallback messageLoopCallback = null; /// /// /// Creates a new thread context object. /// public ThreadContext() { IntPtr address = IntPtr.Zero; UnsafeNativeMethods.DuplicateHandle(new HandleRef(null, SafeNativeMethods.GetCurrentProcess()), new HandleRef(null, SafeNativeMethods.GetCurrentThread()), new HandleRef(null, SafeNativeMethods.GetCurrentProcess()), ref address, 0, false, NativeMethods.DUPLICATE_SAME_ACCESS); handle = address; id = SafeNativeMethods.GetCurrentThreadId(); messageLoopCount = 0; currentThreadContext = this; contextHash[id] = this; } public ApplicationContext ApplicationContext { get { return applicationContext; } } ////// /// Retrieves the component manager for this process. If there is no component manager /// currently installed, we install our own. /// internal UnsafeNativeMethods.IMsoComponentManager ComponentManager { get { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "Application.ComponentManager.Get:"); if (componentManager == null) { // The CLR is a good COM citizen and will pump messages when things are waiting. // This is nice; it keeps the world responsive. But, it is also very hard for // us because most of the code below causes waits, and the likelihood that // a message will come in and need a component manager is very high. Recursing // here is very very bad, and will almost certainly lead to application failure // later on as we come out of the recursion. So, we guard it here and return // null. EVERYONE who accesses the component manager must handle a NULL return! // if (fetchingComponentManager) { return null; } fetchingComponentManager = true; try { UnsafeNativeMethods.IMsoComponentManager msocm = null; Application.OleRequired(); // Attempt to obtain the Host Application MSOComponentManager // IntPtr msgFilterPtr = (IntPtr)0; if (NativeMethods.Succeeded(UnsafeNativeMethods.CoRegisterMessageFilter(NativeMethods.NullHandleRef, ref msgFilterPtr)) && msgFilterPtr != (IntPtr)0) { IntPtr dummy = (IntPtr)0; UnsafeNativeMethods.CoRegisterMessageFilter(new HandleRef(null, msgFilterPtr), ref dummy); object msgFilterObj = Marshal.GetObjectForIUnknown(msgFilterPtr); Marshal.Release(msgFilterPtr); UnsafeNativeMethods.IOleServiceProvider sp = msgFilterObj as UnsafeNativeMethods.IOleServiceProvider; if (sp != null) { try { IntPtr retval = IntPtr.Zero; // PERF ALERT ([....]): Using typeof() of COM object spins up COM at JIT time. // Guid compModGuid = typeof(UnsafeNativeMethods.SMsoComponentManager).GUID; // Guid compModGuid = new Guid("000C060B-0000-0000-C000-000000000046"); Guid iid = new Guid("{000C0601-0000-0000-C000-000000000046}"); int hr = sp.QueryService( ref compModGuid, ref iid, out retval); if (NativeMethods.Succeeded(hr) && retval != IntPtr.Zero) { // Now query for hte message filter. IntPtr pmsocm; try { Guid IID_IMsoComponentManager = typeof(UnsafeNativeMethods.IMsoComponentManager).GUID; hr = Marshal.QueryInterface(retval, ref IID_IMsoComponentManager, out pmsocm); } finally { Marshal.Release(retval); } if (NativeMethods.Succeeded(hr) && pmsocm != IntPtr.Zero) { // Ok, we have a native component manager. Hand this over to // our broker object to get a proxy we can use try { msocm = ComponentManagerBroker.GetComponentManager(pmsocm); } finally { Marshal.Release(pmsocm); } } if (msocm != null) { // If the resulting service is the same pUnk as the // message filter (a common implementation technique), // then we want to null msgFilterObj at this point so // we don't call RelaseComObject on it below. That would // also release the RCW for the component manager pointer. if (msgFilterPtr == retval) { msgFilterObj = null; } externalComponentManager = true; Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "Using MSO Component manager"); // Now attach app domain unload events so we can // detect when we need to revoke our component // AppDomain.CurrentDomain.DomainUnload += new EventHandler(OnDomainUnload); AppDomain.CurrentDomain.ProcessExit += new EventHandler(OnDomainUnload); } } } catch { } } if (msgFilterObj != null && Marshal.IsComObject(msgFilterObj)) { Marshal.ReleaseComObject(msgFilterObj); } } // Otherwise, we implement component manager ourselves // if (msocm == null) { msocm = new ComponentManager(); externalComponentManager = false; // We must also store this back into the message filter for others // to use. // // Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "Using our own component manager"); } if (msocm != null && componentID == INVALID_ID) { // Finally, if we got a compnent manager, register ourselves with it. // Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "Registering MSO component with the component manager"); NativeMethods.MSOCRINFOSTRUCT info = new NativeMethods.MSOCRINFOSTRUCT(); info.cbSize = Marshal.SizeOf(typeof(NativeMethods.MSOCRINFOSTRUCT)); info.uIdleTimeInterval = 0; info.grfcrf = NativeMethods.MSOCM.msocrfPreTranslateAll | NativeMethods.MSOCM.msocrfNeedIdleTime; info.grfcadvf = NativeMethods.MSOCM.msocadvfModal; bool result = msocm.FRegisterComponent(this, info, out componentID); Debug.Assert(componentID != INVALID_ID, "Our ID sentinel was returned as a valid ID"); if (result && !(msocm is ComponentManager)) { messageLoopCount++; } Debug.Assert(result, "Failed to register WindowsForms with the ComponentManager -- DoEvents and modal dialogs will be broken. size: " + info.cbSize); Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager.FRegisterComponent returned " + result.ToString()); Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager.FRegisterComponent assigned a componentID == [0x" + Convert.ToString(componentID, 16) + "]"); componentManager = msocm; } } finally { fetchingComponentManager = false; } } return componentManager; } } internal bool CustomThreadExceptionHandlerAttached { get { return threadExceptionHandler != null; } } ////// /// Retrieves the actual parking form. This will demand create the parking window /// if it needs to. /// ///internal ParkingWindow ParkingWindow { get { // Locking 'this' here is ok since this is an internal class. See VSW#464499. lock(this) { if (parkingWindow == null) { #if DEBUG // if we use Debug.WriteLine instead of "if", we need extra security permissions // to get the stack trace! if (CoreSwitches.PerfTrack.Enabled) { Debug.WriteLine("Creating parking form!"); Debug.WriteLine(CoreSwitches.PerfTrack.Enabled, Environment.StackTrace); } #endif // SECREVIEW : We need to create the parking window. Since this is a top // : level hidden form, we must assert this. However, the parking // : window is complete internal to the assembly, so no one can // : ever get at it. // IntSecurity.ManipulateWndProcAndHandles.Assert(); try { parkingWindow = new ParkingWindow(); } finally { CodeAccessPermission.RevertAssert(); } } return parkingWindow; } } } internal Control ActivatingControl { get { if ((activatingControlRef != null) && (activatingControlRef.IsAlive)) { return activatingControlRef.Target as Control; } return null; } set { if (value != null) { activatingControlRef = new WeakReference(value); } else { activatingControlRef = null; } } } /// /// /// Retrieves the actual parking form. This will demand create the MarshalingControl window /// if it needs to. /// ///internal Control MarshalingControl { get { lock (this) { if (marshalingControl == null) { #if DEBUG // if we use Debug.WriteLine instead of "if", we need extra security permissions // to get the stack trace! if (CoreSwitches.PerfTrack.Enabled) { Debug.WriteLine("Creating marshalling control!"); Debug.WriteLine(CoreSwitches.PerfTrack.Enabled, Environment.StackTrace); } #endif marshalingControl = new System.Windows.Forms.Application.MarshalingControl(); } return marshalingControl; } } } /// /// /// Allows you to setup a message filter for the application's message pump. This /// installs the filter on the current thread. /// ///internal void AddMessageFilter(IMessageFilter f) { if (messageFilters == null) { messageFilters = new ArrayList(); } if (f != null) { SetState(STATE_FILTERSNAPSHOTVALID, false); if (messageFilters.Count > 0 && f is IMessageModifyAndFilter) { // insert the IMessageModifyAndFilter filters first messageFilters.Insert(0, f); } else { messageFilters.Add(f); } } } // Called immediately before we begin pumping messages for a modal message loop. internal void BeginModalMessageLoop(ApplicationContext context) { #if DEBUG debugModalCounter++; #endif // Set the ourModalLoop flag so that the "IMSOComponent.OnEnterState" is a NOOP since we started the ModalMessageLoop. bool wasOurLoop = ourModalLoop; ourModalLoop = true; try { UnsafeNativeMethods.IMsoComponentManager cm = ComponentManager; if (cm != null) { cm.OnComponentEnterState(componentID, NativeMethods.MSOCM.msocstateModal, NativeMethods.MSOCM.msoccontextAll, 0, 0, 0); } } finally { ourModalLoop = wasOurLoop; } // This will initialize the ThreadWindows with proper flags. DisableWindowsForModalLoop(false, context); // onlyWinForms = false modalCount++; if (enterModalHandler != null && modalCount == 1) { enterModalHandler(Thread.CurrentThread, EventArgs.Empty); } } // Disables windows in preparation of going modal. If parameter is true, we disable all // windows, if false, only windows forms windows (i.e., windows controlled by this MsoComponent). // See also IMsoComponent.OnEnterState. internal void DisableWindowsForModalLoop(bool onlyWinForms, ApplicationContext context) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : Entering modal state"); ThreadWindows old = threadWindows; threadWindows = new ThreadWindows(onlyWinForms); threadWindows.Enable(false); threadWindows.previousThreadWindows = old; ModalApplicationContext modalContext = context as ModalApplicationContext; if (modalContext != null) { modalContext.DisableThreadWindows(true, onlyWinForms); } } /// /// /// Disposes this thread context object. Note that this will marshal to the owning thread. /// ///internal void Dispose(bool postQuit) { // need to avoid multiple threads coming in here or we'll leak the thread // handle. // lock (this) { try { if (disposeCount++ == 0) { // make sure that we are not reentrant // Unravel our message loop. this will marshal us over to // the right thread, making the dispose() method async. if (messageLoopCount > 0 && postQuit) { PostQuit(); } else { bool ourThread = SafeNativeMethods.GetCurrentThreadId() == id; try { // We can only clean up if we're being called on our // own thread. // if (ourThread) { // If we had a component manager, detach from it. // if (componentManager != null) { RevokeComponent(); // } // DisposeAssociatedComponents(); DisposeThreadWindows(); try { Application.RaiseThreadExit(); } finally { if (GetState(STATE_OLEINITIALIZED) && !GetState(STATE_EXTERNALOLEINIT)) { SetState(STATE_OLEINITIALIZED, false); UnsafeNativeMethods.OleUninitialize(); } } } } finally { // We can always clean up this handle, though // if (handle != IntPtr.Zero) { UnsafeNativeMethods.CloseHandle(new HandleRef(this, handle)); handle = IntPtr.Zero; } try { if (totalMessageLoopCount == 0) { Application.RaiseExit(); } } finally { contextHash.Remove((object)id); if (currentThreadContext == this) { currentThreadContext = null; } } } } GC.SuppressFinalize(this); } } finally { disposeCount--; } } } /// /// /// Disposes of this thread's parking form. /// ///private void DisposeParkingWindow() { if (parkingWindow != null && parkingWindow.IsHandleCreated) { // We take two paths here. If we are on the same thread as // the parking window, we can destroy its handle. If not, // we just null it and let it GC. When it finalizes it // will disconnect its handle and post a WM_CLOSE. // // It is important that we just call DestroyHandle here // and do not call Dispose. Otherwise we would destroy // controls that are living on the parking window. // int pid; int hwndThread = SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(parkingWindow, parkingWindow.Handle), out pid); int currentThread = SafeNativeMethods.GetCurrentThreadId(); if (hwndThread == currentThread) { parkingWindow.Destroy(); } else { parkingWindow = null; } } } /// /// /// Gets rid of all windows in this thread context. Nulls out /// window objects that we hang on to. /// internal void DisposeThreadWindows() { // We dispose the main window first, so it can perform any // cleanup that it may need to do. // try { if (applicationContext != null) { applicationContext.Dispose(); applicationContext = null; } // Then, we rudely destroy all of the windows on the thread // ThreadWindows tw = new ThreadWindows(true); tw.Dispose(); // And dispose the parking form, if it isn't already // DisposeParkingWindow(); } catch { } } // Enables windows in preparation of stopping modal. If parameter is true, we enable all windows, // if false, only windows forms windows (i.e., windows controlled by this MsoComponent). // See also IMsoComponent.OnEnterState. internal void EnableWindowsForModalLoop(bool onlyWinForms, ApplicationContext context) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : Leaving modal state"); if (threadWindows != null) { threadWindows.Enable(true); Debug.Assert(threadWindows != null, "OnEnterState recursed, but it's not supposed to be reentrant"); threadWindows = threadWindows.previousThreadWindows; } ModalApplicationContext modalContext = context as ModalApplicationContext; if (modalContext != null) { modalContext.DisableThreadWindows(false, onlyWinForms); } } // Called immediately after we end pumping messages for a modal message loop. internal void EndModalMessageLoop(ApplicationContext context) { #if DEBUG debugModalCounter--; Debug.Assert(debugModalCounter >= 0, "Mis-matched calls to Application.BeginModalMessageLoop() and Application.EndModalMessageLoop()"); #endif // This will re-enable the windows... EnableWindowsForModalLoop(false, context); // onlyWinForms = false bool wasOurLoop = ourModalLoop; ourModalLoop = true; try { // If We started the ModalMessageLoop .. this will call us back on the IMSOComponent.OnStateEnter and not do anything ... UnsafeNativeMethods.IMsoComponentManager cm = ComponentManager; if (cm != null) { cm.FOnComponentExitState(componentID, NativeMethods.MSOCM.msocstateModal, NativeMethods.MSOCM.msoccontextAll, 0, 0); } } finally { // Reset the flag since we are exiting out of a ModalMesaageLoop.. ourModalLoop = wasOurLoop; } modalCount--; if (leaveModalHandler != null && modalCount == 0) { leaveModalHandler(Thread.CurrentThread, EventArgs.Empty); } } ////// /// Exits the program by disposing of all thread contexts and message loops. /// ///internal static void ExitApplication() { ExitCommon(true /*disposing*/); } private static void ExitCommon(bool disposing) { lock(tcInternalSyncObject) { if (contextHash != null) { ThreadContext[] ctxs = new ThreadContext[contextHash.Values.Count]; contextHash.Values.CopyTo(ctxs, 0); for (int i = 0; i < ctxs.Length; ++i) { if (ctxs[i].ApplicationContext != null) { ctxs[i].ApplicationContext.ExitThread(); } else { ctxs[i].Dispose(disposing); } } } } } /// /// /// Exits the program by disposing of all thread contexts and message loops. /// ///internal static void ExitDomain() { ExitCommon(false /*disposing*/); } /// /// /// Our finalization. Minimal stuff... this shouldn't be called... We should always be disposed. /// ///~ThreadContext() { // VSWhidbey 169487 We used to call OleUninitialize() here if we were // still STATE_OLEINITIALIZED, but that's never the correct thing to do. // At this point we're on the wrong thread and we should never have been // called here in the first place. // We can always clean up this handle, though // if (handle != IntPtr.Zero) { UnsafeNativeMethods.CloseHandle(new HandleRef(this, handle)); handle = IntPtr.Zero; } } // When a Form receives a WM_ACTIVATE message, it calls this method so we can do the // appropriate MsoComponentManager activation magic internal void FormActivated(bool activate) { if (activate) { UnsafeNativeMethods.IMsoComponentManager cm = ComponentManager; if (cm != null && !(cm is ComponentManager)) { cm.FOnComponentActivate(componentID); } } } // Sets this component as the tracking component - trumping any active component // for message filtering. internal void TrackInput(bool track) { // VSWhidbey 409264 // protect against double setting, as this causes asserts in the VS component manager. if (track != GetState(STATE_TRACKINGCOMPONENT)) { UnsafeNativeMethods.IMsoComponentManager cm = ComponentManager; if (cm != null && !(cm is ComponentManager)) { cm.FSetTrackingComponent(componentID, track); SetState(STATE_TRACKINGCOMPONENT, track); } } } /// /// /// Retrieves a ThreadContext object for the current thread /// ///internal static ThreadContext FromCurrent() { ThreadContext context = currentThreadContext; if (context == null) { context = new ThreadContext(); } return context; } /// /// /// Retrieves a ThreadContext object for the given thread ID /// ///internal static ThreadContext FromId(int id) { ThreadContext context = (ThreadContext)contextHash[(object)id]; if (context == null && id == SafeNativeMethods.GetCurrentThreadId()) { context = new ThreadContext(); } return context; } /// /// /// Determines if it is OK to allow an application to quit and shutdown /// the runtime. We only allow this if we own the base message pump. /// internal bool GetAllowQuit() { return totalMessageLoopCount > 0 && baseLoopReason == NativeMethods.MSOCM.msoloopMain; } ////// /// Retrieves the handle to this thread. /// ///internal IntPtr GetHandle() { return handle; } /// /// /// Retrieves the ID of this thread. /// ///internal int GetId() { return id; } /// /// /// Retrieves the culture for this thread. /// ///internal CultureInfo GetCulture() { if (culture == null || culture.LCID != SafeNativeMethods.GetThreadLocale()) culture = new CultureInfo(SafeNativeMethods.GetThreadLocale()); return culture; } /// /// /// Determines if a message loop exists on this thread. /// internal bool GetMessageLoop() { return GetMessageLoop(false); } ////// /// Determines if a message loop exists on this thread. /// internal bool GetMessageLoop(bool mustBeActive) { // If we are already running a loop, we're fine. // If we are running in external manager we may need to make sure first the loop is active // if (messageLoopCount > (mustBeActive && externalComponentManager ? 1 : 0)) { return true; } // Also, access the ComponentManager property to demand create it, and we're also // fine if it is an external manager, because it has already pushed a loop. // if (ComponentManager != null && externalComponentManager) { if (mustBeActive == false) { return true; } UnsafeNativeMethods.IMsoComponent[] activeComponents = new UnsafeNativeMethods.IMsoComponent[1]; if (ComponentManager.FGetActiveComponent(NativeMethods.MSOCM.msogacActive, activeComponents, null, 0) && activeComponents[0] == this) { return true; } } // Finally, check if a message loop has been registered MessageLoopCallback callback = messageLoopCallback; if (callback != null) { return callback(); } // Otherwise, we do not have a loop running. // return false; } private bool GetState(int bit) { return(threadState & bit) != 0; } ////// Keep the object alive forever. /// public override object InitializeLifetimeService() { return null; } ////// A method of determining whether we are handling messages that does not demand register /// the componentmanager /// ///internal bool IsValidComponentId() { return (componentID != INVALID_ID); } internal System.Threading.ApartmentState OleRequired() { Thread current = Thread.CurrentThread; if (!GetState(STATE_OLEINITIALIZED)) { int ret = UnsafeNativeMethods.OleInitialize(); #if false // PERFTRACK : [....], 7/26/1999 - To avoid constructing the string in // : non-failure cases (vast majority), we will do the debug.fail // : inside an if statement. // if (!(ret == NativeMethods.S_OK || ret == NativeMethods.S_FALSE || ret == NativeMethods.RPC_E_CHANGED_MODE)) { Debug.Assert(ret == NativeMethods.S_OK || ret == NativeMethods.S_FALSE || ret == NativeMethods.RPC_E_CHANGED_MODE, "OLE Failed to Initialize!. RetCode: 0x" + Convert.ToString(ret, 16) + " LastError: " + Marshal.GetLastWin32Error().ToString()); } #endif SetState(STATE_OLEINITIALIZED, true); if (ret == NativeMethods.RPC_E_CHANGED_MODE) { // This could happen if the thread was already initialized for MTA // and then we call OleInitialize which tries to initialized it for STA // This currently happens while profiling... SetState(STATE_EXTERNALOLEINIT, true); } } if ( GetState( STATE_EXTERNALOLEINIT )) { return System.Threading.ApartmentState.MTA; } else { return System.Threading.ApartmentState.STA; } } private void OnAppThreadExit(object sender, EventArgs e) { Dispose(true); } /// /// Revokes our component if needed. /// [PrePrepareMethod] private void OnDomainUnload(object sender, EventArgs e) { RevokeComponent(); ExitDomain(); } ////// /// Called when an untrapped exception occurs in a thread. This allows the /// programmer to trap these, and, if left untrapped, throws a standard error /// dialog. /// ///internal void OnThreadException(Exception t) { if (GetState(STATE_INTHREADEXCEPTION)) return; SetState(STATE_INTHREADEXCEPTION, true); try { if (threadExceptionHandler != null) { threadExceptionHandler(Thread.CurrentThread, new ThreadExceptionEventArgs(t)); } else { if (SystemInformation.UserInteractive) { ThreadExceptionDialog td = new ThreadExceptionDialog(t); DialogResult result = DialogResult.OK; // SECREVIEW : This Assert is ok, this dialog shows up when the application is about to die. // ShowDialog will generate a call to ContainerControl.SetActiveControl which demands // ModifyFocus permission, need to assert it here. // IntSecurity.ModifyFocus.Assert(); try { result = td.ShowDialog(); } finally { CodeAccessPermission.RevertAssert(); td.Dispose(); } switch (result) { case DialogResult.Abort: // SECREVIEW : The user clicked "Quit" in response to a exception dialog. // : We only show the quit option when we own the message pump, // : so this won't ever tear down IE or any other ActiveX host. // : // : This has a potential problem where a component could // : cause a failure, then try a "trick" the user into hitting // : quit. However, no component or application outside of // : the windows forms assembly can modify the dialog, so this is // : a really minor concern. // Application.ExitInternal(); // SECREVIEW : We can't revert this assert... after Exit(0) is called, no // : more code is executed... // new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); Environment.Exit(0); break; case DialogResult.Yes: WarningException w = t as WarningException; if (w != null) { Help.ShowHelp(null, w.HelpUrl, w.HelpTopic); } break; } } else { // Ignore unhandled thread exceptions. The user can // override if they really care. // } } } finally { SetState(STATE_INTHREADEXCEPTION, false); } } internal void PostQuit() { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : Attempting to terminate message loop"); // Per http://support.microsoft.com/support/kb/articles/Q183/1/16.ASP // // WM_QUIT may be consumed by another message pump under very specific circumstances. // When that occurs, we rely on the STATE_POSTEDQUIT to be caught in the next // idle, at which point we can tear down. // // We can't follow the KB article exactly, becasue we don't have an HWND to PostMessage // to. // UnsafeNativeMethods.PostThreadMessage(id, NativeMethods.WM_QUIT, IntPtr.Zero, IntPtr.Zero); SetState(STATE_POSTEDQUIT, true); } // Allows the hosting environment to register a callback internal void RegisterMessageLoop(MessageLoopCallback callback) { messageLoopCallback = callback; } /// /// /// Removes a message filter previously installed with addMessageFilter. /// ///internal void RemoveMessageFilter(IMessageFilter f) { if (messageFilters != null) { SetState(STATE_FILTERSNAPSHOTVALID, false); messageFilters.Remove(f); } } /// /// /// Starts a message loop for the given reason. /// ///internal void RunMessageLoop(int reason, ApplicationContext context) { // Ensure that we attempt to apply theming before doing anything // that might create a window. IntPtr userCookie = IntPtr.Zero; if (useVisualStyles) { userCookie = UnsafeNativeMethods.ThemingScope.Activate(); } try { RunMessageLoopInner(reason, context); } finally { UnsafeNativeMethods.ThemingScope.Deactivate(userCookie); } } private void RunMessageLoopInner(int reason, ApplicationContext context) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ThreadContext.PushMessageLoop {"); Debug.Indent(); if (reason == NativeMethods.MSOCM.msoloopModalForm && !SystemInformation.UserInteractive) { throw new InvalidOperationException(SR.GetString(SR.CantShowModalOnNonInteractive)); } // if we've entered because of a Main message loop being pushed // (different than a modal message loop or DoEVents loop) // then clear the QUIT flag to allow normal processing. // this flag gets set during loop teardown for another form. if (reason == NativeMethods.MSOCM.msoloopMain) { SetState(STATE_POSTEDQUIT, false); } if (totalMessageLoopCount++ == 0) { baseLoopReason = reason; } messageLoopCount++; if (reason == NativeMethods.MSOCM.msoloopMain) { // If someone has tried to push another main message loop on this thread, ignore // it. if (messageLoopCount != 1) { throw new InvalidOperationException(SR.GetString(SR.CantNestMessageLoops)); } applicationContext = context; applicationContext.ThreadExit += new EventHandler(OnAppThreadExit); if (applicationContext.MainForm != null) { applicationContext.MainForm.Visible = true; } } Form oldForm = currentForm; if (context != null) { currentForm = context.MainForm; } bool fullModal = false; bool localModal = false; HandleRef hwndOwner = new HandleRef(null, IntPtr.Zero); if (reason == NativeMethods.MSOCM.msoloopDoEventsModal) { localModal = true; } if (reason == NativeMethods.MSOCM.msoloopModalForm || reason == NativeMethods.MSOCM.msoloopModalAlert) { fullModal = true; // We're about to disable all windows in the thread so our modal dialog can be the top dog. Because this can interact // with external MSO things, and also because the modal dialog could have already had its handle created, // Check to see if the handle exists and if the window is currently enabled. We remember this so we can set the // window back to enabled after disabling everyone else. This is just a precaution against someone doing the // wrong thing and disabling our dialog. // bool modalEnabled = currentForm != null && currentForm.Enabled; Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "[0x" + Convert.ToString(componentID, 16) + "] Notifying component manager that we are entering a modal loop"); BeginModalMessageLoop(context); // If the owner window of the dialog is still enabled, disable it now. // This can happen if the owner window is from a different thread or // process. hwndOwner = new HandleRef(null, UnsafeNativeMethods.GetWindowLong(new HandleRef(currentForm, currentForm.Handle), NativeMethods.GWL_HWNDPARENT)); if (hwndOwner.Handle != IntPtr.Zero) { if (SafeNativeMethods.IsWindowEnabled(hwndOwner)) { SafeNativeMethods.EnableWindow(hwndOwner, false); } else { // reset hwndOwner so we are not tempted to // fiddle with it hwndOwner = new HandleRef(null, IntPtr.Zero); } } // The second half of the the modalEnabled flag above. Here, if we were previously // enabled, make sure that's still the case. // if (currentForm != null && currentForm.IsHandleCreated && SafeNativeMethods.IsWindowEnabled(new HandleRef(currentForm, currentForm.Handle)) != modalEnabled) { SafeNativeMethods.EnableWindow(new HandleRef(currentForm, currentForm.Handle), modalEnabled); } } try { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "[0x" + Convert.ToString(componentID, 16) + "] Calling ComponentManager.FPushMessageLoop..."); bool result; // Register marshaller for background tasks. At this point, // need to be able to successfully get the handle to the // parking window. Only do it when we're entering the first // message loop for this thread. if (messageLoopCount == 1) { WindowsFormsSynchronizationContext.InstallIfNeeded(); } //need to do this in a try/finally. Also good to do after we installed the synch context. if (fullModal && currentForm != null) { currentForm.Visible = true; } if ((!fullModal && !localModal) || ComponentManager is ComponentManager) { result = ComponentManager.FPushMessageLoop(componentID, reason, 0); } else if (reason == NativeMethods.MSOCM.msoloopDoEvents || reason == NativeMethods.MSOCM.msoloopDoEventsModal) { result = LocalModalMessageLoop(null); } else { result = LocalModalMessageLoop(currentForm); } Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "[0x" + Convert.ToString(componentID, 16) + "] ComponentManager.FPushMessageLoop returned " + result.ToString()); } finally { if (fullModal) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "[0x" + Convert.ToString(componentID, 16) + "] Notifying component manager that we are exiting a modal loop"); EndModalMessageLoop(context); // Again, if the hwndOwner was valid and disabled above, re-enable it. if (hwndOwner.Handle != IntPtr.Zero) { SafeNativeMethods.EnableWindow(hwndOwner, true); } } currentForm = oldForm; totalMessageLoopCount--; messageLoopCount--; if (messageLoopCount == 0) { // If last message loop shutting down, install the // previous op [....] context in place before we started the first // message loop. WindowsFormsSynchronizationContext.Uninstall(false); } if (reason == NativeMethods.MSOCM.msoloopMain) { Dispose(true); } else if (messageLoopCount == 0 && componentManager != null) { // If we had a component manager, detach from it. // RevokeComponent(); } } Debug.Unindent(); Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "}"); } private bool LocalModalMessageLoop(Form form) { try { // Execute the message loop until the active component tells us to stop. // NativeMethods.MSG msg = new NativeMethods.MSG(); bool unicodeWindow = false; bool continueLoop = true; while (continueLoop) { bool peeked = UnsafeNativeMethods.PeekMessage(ref msg, NativeMethods.NullHandleRef, 0, 0, NativeMethods.PM_NOREMOVE); if (peeked) { // If the component wants us to process the message, do it. // The component manager hosts windows from many places. We must be sensitive // to ansi / Unicode windows here. // if (msg.hwnd != IntPtr.Zero && SafeNativeMethods.IsWindowUnicode(new HandleRef(null, msg.hwnd))) { unicodeWindow = true; if (!UnsafeNativeMethods.GetMessageW(ref msg, NativeMethods.NullHandleRef, 0, 0)) { continue; } } else { unicodeWindow = false; if (!UnsafeNativeMethods.GetMessageA(ref msg, NativeMethods.NullHandleRef, 0, 0)) { continue; } } if (!PreTranslateMessage(ref msg)) { UnsafeNativeMethods.TranslateMessage(ref msg); if (unicodeWindow) { UnsafeNativeMethods.DispatchMessageW(ref msg); } else { UnsafeNativeMethods.DispatchMessageA(ref msg); } } if (form != null) { continueLoop = !form.CheckCloseDialog(false); } } else if (form == null) { break; } else if (!UnsafeNativeMethods.PeekMessage(ref msg, NativeMethods.NullHandleRef, 0, 0, NativeMethods.PM_NOREMOVE)) { UnsafeNativeMethods.WaitMessage(); } } return continueLoop; } catch { return false; } } internal bool ProcessFilters(ref NativeMethods.MSG msg, out bool modified) { bool filtered = false; modified = false; // Account for the case where someone removes a message filter // as a result of PreFilterMessage. the message filter will be // removed from _the next_ message. if (messageFilters != null && !GetState(STATE_FILTERSNAPSHOTVALID)) { if (messageFilters.Count > 0) { messageFilterSnapshot = new IMessageFilter[messageFilters.Count]; messageFilters.CopyTo(messageFilterSnapshot); } else { messageFilterSnapshot = null; } SetState(STATE_FILTERSNAPSHOTVALID, true); } if (messageFilterSnapshot != null) { IMessageFilter f; int count = messageFilterSnapshot.Length; Message m = Message.Create(msg.hwnd, msg.message, msg.wParam, msg.lParam); for (int i = 0; i < count; i++) { f = (IMessageFilter)messageFilterSnapshot[i]; bool filterMessage = f.PreFilterMessage(ref m); // make sure that we update the msg struct with the new result after the call to // PreFilterMessage. if (f is IMessageModifyAndFilter) { msg.hwnd = m.HWnd; msg.message = m.Msg; msg.wParam = m.WParam; msg.lParam = m.LParam; modified = true; } if (filterMessage) { // consider : m is by ref here, so the user can change it. But we // are discarding changes by not propagating to msg. Should we? filtered = true; break; } } } return filtered; } /// /// Message filtering routine that is called before dispatching a message. /// If this returns true, the message is already processed. If it returns /// false, the message should be allowed to continue through the dispatch /// mechanism. /// internal bool PreTranslateMessage(ref NativeMethods.MSG msg) { bool modified = false; if (ProcessFilters(ref msg, out modified)) { return true; } if (msg.message >= NativeMethods.WM_KEYFIRST && msg.message <= NativeMethods.WM_KEYLAST) { if (msg.message == NativeMethods.WM_CHAR) { int breakLParamMask = 0x1460000; // 1 = extended keyboard, 46 = scan code if ((int)msg.wParam == 3 && ((int)msg.lParam & breakLParamMask) == breakLParamMask) { // ctrl-brk // wParam is the key character, which for ctrl-brk is the same as ctrl-C. // So we need to go to the lparam to distinguish the two cases. // You might also be able to do this with WM_KEYDOWN (again with wParam=3) if (Debugger.IsAttached) { Debugger.Break(); } } } Control target = Control.FromChildHandleInternal(msg.hwnd); bool retValue = false; Message m = Message.Create(msg.hwnd, msg.message, msg.wParam, msg.lParam); if (target != null) { if (NativeWindow.WndProcShouldBeDebuggable) { // we don't want to do a catch in the debuggable case. // if (Control.PreProcessControlMessageInternal(target, ref m) == PreProcessControlState.MessageProcessed) { retValue = true; } } else { try { if (Control.PreProcessControlMessageInternal(target, ref m) == PreProcessControlState.MessageProcessed) { retValue = true; } } catch (Exception e) { OnThreadException(e); } } } else { // See if this is a dialog message -- this is for handling any native dialogs that are launched from // winforms code. This can happen with ActiveX controls that launch dialogs specificially // // first, get the first top-level window in the hierarchy. // IntPtr hwndRoot = UnsafeNativeMethods.GetAncestor(new HandleRef(null, msg.hwnd), NativeMethods.GA_ROOT); // if we got a valid HWND, then call IsDialogMessage on it. If that returns true, it's been processed // so we should return true to prevent Translate/Dispatch from being called. // if (hwndRoot != IntPtr.Zero && UnsafeNativeMethods.IsDialogMessage(new HandleRef(null, hwndRoot), ref msg)) { return true; } } msg.wParam = m.WParam; msg.lParam = m.LParam; if (retValue) { return true; } } return false; } ////// Revokes our component from the active component manager. Does /// nothing if there is no active component manager or we are /// already invoked. /// private void RevokeComponent() { if (componentManager != null && componentID != INVALID_ID) { int id = componentID; UnsafeNativeMethods.IMsoComponentManager msocm = componentManager; try { msocm.FRevokeComponent(id); if (Marshal.IsComObject(msocm)) { Marshal.ReleaseComObject(msocm); } } finally { componentManager = null; componentID = INVALID_ID; } } } ////// /// Sets the culture for this thread. /// ///internal void SetCulture(CultureInfo culture) { if (culture != null && culture.LCID != SafeNativeMethods.GetThreadLocale()) { SafeNativeMethods.SetThreadLocale(culture.LCID); } } private void SetState(int bit, bool value) { if (value) { threadState |= bit; } else { threadState &= (~bit); } } /////////////////////////////////////////////////////////////////////////////////////////////////////// /*************************************************************************************** * * IMsoComponent * ****************************************************************************************/ // Things to test in VS when you change this code: // - You can bring up dialogs multiple times (ie, the editor for TextBox.Lines -- ASURT 41876) // - Double-click DataFormWizard, cancel wizard (ASURT 41562) // - When a dialog is open and you switch to another application, when you switch // back to VS the dialog gets the focus (ASURT 38961) // - If one modal dialog launches another, they are all modal (ASURT 37154. Try web forms Table\Rows\Cell) // - When a dialog is up, VS is completely disabled, including moving and resizing VS. // - After doing all this, you can ctrl-shift-N start a new project and VS is enabled. /// /// /// Standard FDebugMessage method. /// Since IMsoComponentManager is a reference counted interface, /// MsoDWGetChkMemCounter should be used when processing the /// msodmWriteBe message. /// bool UnsafeNativeMethods.IMsoComponent.FDebugMessage(IntPtr hInst, int msg, IntPtr wparam, IntPtr lparam) { return false; } ////// /// Give component a chance to process the message pMsg before it is /// translated and dispatched. Component can do TranslateAccelerator /// do IsDialogMessage, modify pMsg, or take some other action. /// Return TRUE if the message is consumed, FALSE otherwise. /// bool UnsafeNativeMethods.IMsoComponent.FPreTranslateMessage(ref NativeMethods.MSG msg) { return PreTranslateMessage(ref msg); } ////// /// Notify component when app enters or exits (as indicated by fEnter) /// the state identified by uStateID (a value from olecstate enumeration). /// Component should take action depending on value of uStateID /// (see olecstate comments, above). /// /// Note: If n calls are made with TRUE fEnter, component should consider /// the state to be in effect until n calls are made with FALSE fEnter. /// /// Note: Components should be aware that it is possible for this method to /// be called with FALSE fEnter more times than it was called with TRUE /// fEnter (so, for example, if component is maintaining a state counter /// (incremented when this method is called with TRUE fEnter, decremented /// when called with FALSE fEnter), the counter should not be decremented /// for FALSE fEnter if it is already at zero.) /// void UnsafeNativeMethods.IMsoComponent.OnEnterState(int uStateID, bool fEnter) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : OnEnterState(" + uStateID + ", " + fEnter + ")"); // Return if our (WINFORMS) Modal Loop is still running. if (ourModalLoop) { return; } if (uStateID == NativeMethods.MSOCM.msocstateModal) { // We should only be messing with windows we own. See the "ctrl-shift-N" test above. if (fEnter) { DisableWindowsForModalLoop(true, null); // WinFormsOnly = true } else { EnableWindowsForModalLoop(true, null); // WinFormsOnly = true } } } ////// /// Notify component when the host application gains or loses activation. /// If fActive is TRUE, the host app is being activated and dwOtherThreadID /// is the ID of the thread owning the window being deactivated. /// If fActive is FALSE, the host app is being deactivated and /// dwOtherThreadID is the ID of the thread owning the window being /// activated. /// Note: this method is not called when both the window being activated /// and the one being deactivated belong to the host app. /// void UnsafeNativeMethods.IMsoComponent.OnAppActivate(bool fActive, int dwOtherThreadID) { } ////// /// Notify the active component that it has lost its active status because /// the host or another component has become active. /// void UnsafeNativeMethods.IMsoComponent.OnLoseActivation() { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : Our component is losing activation."); } ////// /// Notify component when a new object is being activated. /// If pic is non-NULL, then it is the component that is being activated. /// In this case, fSameComponent is TRUE if pic is the same component as /// the callee of this method, and pcrinfo is the reg info of pic. /// If pic is NULL and fHostIsActivating is TRUE, then the host is the /// object being activated, and pchostinfo is its host info. /// If pic is NULL and fHostIsActivating is FALSE, then there is no current /// active object. /// /// If pic is being activated and pcrinfo->grf has the /// olecrfExclusiveBorderSpace bit set, component should hide its border /// space tools (toolbars, status bars, etc.); /// component should also do this if host is activating and /// pchostinfo->grfchostf has the olechostfExclusiveBorderSpace bit set. /// In either of these cases, component should unhide its border space /// tools the next time it is activated. /// /// if pic is being activated and pcrinfo->grf has the /// olecrfExclusiveActivation bit is set, then pic is being activated in /// "ExclusiveActive" mode. /// Component should retrieve the top frame window that is hosting pic /// (via pic->HwndGetWindow(olecWindowFrameToplevel, 0)). /// If this window is different from component's own top frame window, /// component should disable its windows and do other things it would do /// when receiving OnEnterState(olecstateModal, TRUE) notification. /// Otherwise, if component is top-level, /// it should refuse to have its window activated by appropriately /// processing WM_MOUSEACTIVATE (but see WM_MOUSEACTIVATE NOTE, above). /// Component should remain in one of these states until the /// ExclusiveActive mode ends, indicated by a future call to /// OnActivationChange with ExclusiveActivation bit not set or with NULL /// pcrinfo. /// void UnsafeNativeMethods.IMsoComponent.OnActivationChange(UnsafeNativeMethods.IMsoComponent component, bool fSameComponent, int pcrinfo, bool fHostIsActivating, int pchostinfo, int dwReserved) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : OnActivationChange"); } ////// /// Give component a chance to do idle time tasks. grfidlef is a group of /// bit flags taken from the enumeration of oleidlef values (above), /// indicating the type of idle tasks to perform. /// Component may periodically call IOleComponentManager::FContinueIdle; /// if this method returns FALSE, component should terminate its idle /// time processing and return. /// Return TRUE if more time is needed to perform the idle time tasks, /// FALSE otherwise. /// Note: If a component reaches a point where it has no idle tasks /// and does not need FDoIdle calls, it should remove its idle task /// registration via IOleComponentManager::FUpdateComponentRegistration. /// Note: If this method is called on while component is performing a /// tracking operation, component should only perform idle time tasks that /// it deems are appropriate to perform during tracking. /// bool UnsafeNativeMethods.IMsoComponent.FDoIdle(int grfidlef) { if (idleHandler != null) { idleHandler(Thread.CurrentThread, EventArgs.Empty); } return false; } ////// /// Called during each iteration of a message loop that the component /// pushed. uReason and pvLoopData are the reason and the component private /// data that were passed to IOleComponentManager::FPushMessageLoop. /// This method is called after peeking the next message in the queue /// (via PeekMessage) but before the message is removed from the queue. /// The peeked message is passed in the pMsgPeeked param (NULL if no /// message is in the queue). This method may be additionally called when /// the next message has already been removed from the queue, in which case /// pMsgPeeked is passed as NULL. /// Return TRUE if the message loop should continue, FALSE otherwise. /// If FALSE is returned, the component manager terminates the loop without /// removing pMsgPeeked from the queue. /// bool UnsafeNativeMethods.IMsoComponent.FContinueMessageLoop(int reason, int pvLoopData, NativeMethods.MSG[] msgPeeked) { bool continueLoop = true; // If we get a null message, and we have previously posted the WM_QUIT message, // then someone ate the message... // if (msgPeeked == null && GetState(STATE_POSTEDQUIT)) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : Abnormal loop termination, no WM_QUIT received"); continueLoop = false; } else { switch (reason) { case NativeMethods.MSOCM.msoloopFocusWait: // For focus wait, check to see if we are now the active application. // int pid; SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(null, UnsafeNativeMethods.GetActiveWindow()), out pid); if (pid == SafeNativeMethods.GetCurrentProcessId()) { continueLoop = false; } break; case NativeMethods.MSOCM.msoloopModalAlert: case NativeMethods.MSOCM.msoloopModalForm: // For modal forms, check to see if the current active form has been // dismissed. If there is no active form, then it is an error that // we got into here, so we terminate the loop. // if (currentForm == null || currentForm.CheckCloseDialog(false)) { continueLoop = false; } break; case NativeMethods.MSOCM.msoloopDoEvents: case NativeMethods.MSOCM.msoloopDoEventsModal: // For DoEvents, just see if there are more messages on the queue. // if (!UnsafeNativeMethods.PeekMessage(ref tempMsg, NativeMethods.NullHandleRef, 0, 0, NativeMethods.PM_NOREMOVE)) { continueLoop = false; } break; } } return continueLoop; } ////// /// Called when component manager wishes to know if the component is in a /// state in which it can terminate. If fPromptUser is FALSE, component /// should simply return TRUE if it can terminate, FALSE otherwise. /// If fPromptUser is TRUE, component should return TRUE if it can /// terminate without prompting the user; otherwise it should prompt the /// user, either 1.) asking user if it can terminate and returning TRUE /// or FALSE appropriately, or 2.) giving an indication as to why it /// cannot terminate and returning FALSE. /// bool UnsafeNativeMethods.IMsoComponent.FQueryTerminate(bool fPromptUser) { return true; } ////// /// Called when component manager wishes to terminate the component's /// registration. Component should revoke its registration with component /// manager, release references to component manager and perform any /// necessary cleanup. /// void UnsafeNativeMethods.IMsoComponent.Terminate() { if (this.messageLoopCount > 0 && !(ComponentManager is ComponentManager)) { this.messageLoopCount--; } Dispose(false); } ////// /// Called to retrieve a window associated with the component, as specified /// by dwWhich, a olecWindowXXX value (see olecWindow, above). /// dwReserved is reserved for future use and should be zero. /// Component should return the desired window or NULL if no such window /// exists. /// IntPtr UnsafeNativeMethods.IMsoComponent.HwndGetWindow(int dwWhich, int dwReserved) { return IntPtr.Zero; } } ////// This class allows us to handle sends/posts in our winformssynchcontext on the correct thread via /// control.invoke(). /// ///internal sealed class MarshalingControl : Control { internal MarshalingControl() : base(false) { Visible = false; SetState2(STATE2_INTERESTEDINUSERPREFERENCECHANGED, false); SetTopLevel(true); CreateControl(); CreateHandle(); } protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; // Message only windows are cheaper and have fewer issues than // full blown invisible windows. But, they are only supported // on NT. if (Environment.OSVersion.Platform == PlatformID.Win32NT) { cp.Parent = (IntPtr)NativeMethods.HWND_MESSAGE; } return cp; } } protected override void OnLayout(LayoutEventArgs levent) { } protected override void OnSizeChanged(EventArgs e) { // don't do anything here -- small perf game of avoiding layout, etc. } } /// /// /// This class embodies our parking window, which we create when the /// first message loop is pushed onto the thread. /// ///internal sealed class ParkingWindow : ContainerControl, IArrangedElement { // WHIDBEY CHANGES // in whidbey we now aggressively tear down the parking window // when the last control has been removed off of it. // // private const int WM_CHECKDESTROY = NativeMethods.WM_USER + 0x01; private int childCount = 0; [ SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters") // The parking window is invisible. // So we don't have to localize its Text. ] public ParkingWindow() { SetState2(STATE2_INTERESTEDINUSERPREFERENCECHANGED, false); SetState(STATE_TOPLEVEL, true); Text = "WindowsFormsParkingWindow"; Visible = false; } protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; // Message only windows are cheaper and have fewer issues than // full blown invisible windows. But, they are only supported // on NT. if (Environment.OSVersion.Platform == PlatformID.Win32NT) { cp.Parent = (IntPtr)NativeMethods.HWND_MESSAGE; } return cp; } } internal override void AddReflectChild() { if (childCount < 0) { Debug.Fail("How did parkingwindow childcount go negative???"); childCount = 0; } childCount++; } internal override void RemoveReflectChild() { childCount--; if (childCount < 0) { Debug.Fail("How did parkingwindow childcount go negative???"); childCount = 0; } if (childCount == 0) { if (IsHandleCreated) { //check to see if we are running on the thread that owns the parkingwindow. //if so, we can destroy immediately. //This is important for scenarios where apps leak controls until after the //messagepump is gone and then decide to clean them up. We should clean //up the parkingwindow in this case and a postmessage won't do it. int lpdwProcessId; //unused int id = SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(this, HandleInternal), out lpdwProcessId); Application.ThreadContext ctx = Application.ThreadContext.FromId(id); //We only do this if the ThreadContext tells us that we are currently //handling a window message. if (ctx == null || !Object.ReferenceEquals(ctx, Application.ThreadContext.FromCurrent())) { UnsafeNativeMethods.PostMessage(new HandleRef(this, HandleInternal), WM_CHECKDESTROY, IntPtr.Zero, IntPtr.Zero); } else { CheckDestroy(); } } } } private void CheckDestroy() { if (childCount == 0) { IntPtr hwndChild = UnsafeNativeMethods.GetWindow(new HandleRef(this, Handle), NativeMethods.GW_CHILD); if (hwndChild == IntPtr.Zero) { DestroyHandle(); } } } public void Destroy() { DestroyHandle(); } /// /// "Parks" the given HWND to a temporary HWND. This allows WS_CHILD windows to /// be parked. /// internal void ParkHandle(HandleRef handle) { if (!IsHandleCreated) { CreateHandle(); } UnsafeNativeMethods.SetParent(handle, new HandleRef(this, Handle)); } ////// "Unparks" the given HWND to a temporary HWND. This allows WS_CHILD windows to /// be parked. /// internal void UnparkHandle(HandleRef handle) { if (IsHandleCreated) { Debug.Assert(UnsafeNativeMethods.GetParent(handle) != Handle, "Always set the handle's parent to someone else before calling UnparkHandle"); // If there are no child windows in this handle any longer, destroy the parking window. CheckDestroy(); } } // Do nothing on layout to reduce the calls into the LayoutEngine while debugging. protected override void OnLayout(LayoutEventArgs levent) {} void IArrangedElement.PerformLayout(IArrangedElement affectedElement, string affectedProperty) {} protected override void WndProc(ref Message m) { if (m.Msg != NativeMethods.WM_SHOWWINDOW) { base.WndProc(ref m); if (m.Msg == NativeMethods.WM_PARENTNOTIFY) { if (NativeMethods.Util.LOWORD((int)m.WParam) == NativeMethods.WM_DESTROY) { UnsafeNativeMethods.PostMessage(new HandleRef(this, Handle), WM_CHECKDESTROY, IntPtr.Zero, IntPtr.Zero); } } else if (m.Msg == WM_CHECKDESTROY) { CheckDestroy(); } } } } ////// /// This class enables or disables all windows in the current thread. We use this to /// disable other windows on the thread when a modal dialog is to be shown. It can also /// be used to dispose all windows in a thread, which we do before returning from a message /// loop. /// ///private sealed class ThreadWindows { private IntPtr[] windows; private int windowCount; private IntPtr activeHwnd; private IntPtr focusedHwnd; internal ThreadWindows previousThreadWindows; private bool onlyWinForms = true; internal ThreadWindows(bool onlyWinForms) { windows = new IntPtr[16]; this.onlyWinForms = onlyWinForms; UnsafeNativeMethods.EnumThreadWindows(SafeNativeMethods.GetCurrentThreadId(), new NativeMethods.EnumThreadWindowsCallback(this.Callback), NativeMethods.NullHandleRef); } private bool Callback(IntPtr hWnd, IntPtr lparam) { // We only do visible and enabled windows. Also, we only do top level windows. // Finally, we only include windows that are DNA windows, since other MSO components // will be responsible for disabling their own windows. // if (SafeNativeMethods.IsWindowVisible(new HandleRef(null, hWnd)) && SafeNativeMethods.IsWindowEnabled(new HandleRef(null, hWnd))) { bool add = true; if (onlyWinForms) { Control c = Control.FromHandleInternal(hWnd); if (c == null) add = false; } if (add) { if (windowCount == windows.Length) { IntPtr[] newWindows = new IntPtr[windowCount * 2]; Array.Copy(windows, 0, newWindows, 0, windowCount); windows = newWindows; } windows[windowCount++] = hWnd; } } return true; } // Disposes all top-level Controls on this thread internal void Dispose() { for (int i = 0; i < windowCount; i++) { IntPtr hWnd = windows[i]; if (UnsafeNativeMethods.IsWindow(new HandleRef(null, hWnd))) { Control c = Control.FromHandleInternal(hWnd); if (c != null) { c.Dispose(); } } } } // Enables/disables all top-level Controls on this thread internal void Enable(bool state) { if (!onlyWinForms && !state) { activeHwnd = UnsafeNativeMethods.GetActiveWindow(); Control activatingControl = Application.ThreadContext.FromCurrent().ActivatingControl; if (activatingControl != null) { focusedHwnd = activatingControl.Handle; } else { focusedHwnd = UnsafeNativeMethods.GetFocus(); } } for (int i = 0; i < windowCount; i++) { IntPtr hWnd = windows[i]; Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : Changing enabled on window: " + hWnd.ToString() + " : " + state.ToString()); if (UnsafeNativeMethods.IsWindow(new HandleRef(null, hWnd))) SafeNativeMethods.EnableWindow(new HandleRef(null, hWnd), state); } // VSWhidbey 258748 :OpenFileDialog is not returning the focus the way other dialogs do. // Important that we re-activate the old window when we are closing // our modal dialog. // // VS Whidbey 337882: edit mode forever with Excel application // But, DON'T dink around with other people's state when we're simply // responding to external MSOCM events about modality. When we are, // we are created with a TRUE for onlyWinForms. if (!onlyWinForms && state) { if (activeHwnd != IntPtr.Zero && UnsafeNativeMethods.IsWindow(new HandleRef(null, activeHwnd))) { UnsafeNativeMethods.SetActiveWindow(new HandleRef(null, activeHwnd)); } if (focusedHwnd != IntPtr.Zero && UnsafeNativeMethods.IsWindow(new HandleRef(null, focusedHwnd))) { UnsafeNativeMethods.SetFocus(new HandleRef(null, focusedHwnd)); } } } } private class ModalApplicationContext : ApplicationContext { private ThreadContext parentWindowContext; private delegate void ThreadWindowCallback(ThreadContext context, bool onlyWinForms); public ModalApplicationContext(Form modalForm) : base(modalForm) { } public void DisableThreadWindows(bool disable, bool onlyWinForms) { Control parentControl = null; // VSWhidbey 400973 get ahold of the parent HWND -- if it's a different thread we need to do // do the disable over there too. Note we only do this if we're parented by a Windows Forms // parent. // if (MainForm != null && MainForm.IsHandleCreated) { // get ahold of the parenting control // IntPtr parentHandle = UnsafeNativeMethods.GetWindowLong(new HandleRef(this, MainForm.Handle), NativeMethods.GWL_HWNDPARENT); parentControl = Control.FromHandleInternal(parentHandle); if (parentControl != null && parentControl.InvokeRequired) { parentWindowContext = GetContextForHandle(new HandleRef(this, parentHandle)); } else { parentWindowContext = null; } } // if we got a thread context, that means our parent is in a different thread, make the call on that thread. // if (parentWindowContext != null) { // in case we've already torn down, ask the context for this. // if (parentControl == null) { parentControl = parentWindowContext.ApplicationContext.MainForm; } if (disable) { parentControl.Invoke(new ThreadWindowCallback(DisableThreadWindowsCallback), new object[]{parentWindowContext, onlyWinForms}); } else { parentControl.Invoke(new ThreadWindowCallback(EnableThreadWindowsCallback), new object[]{parentWindowContext, onlyWinForms}); } } } private void DisableThreadWindowsCallback(ThreadContext context, bool onlyWinForms) { context.DisableWindowsForModalLoop(onlyWinForms, this); } private void EnableThreadWindowsCallback(ThreadContext context, bool onlyWinForms) { context.EnableWindowsForModalLoop(onlyWinForms, this); } protected override void ExitThreadCore() { // do nothing... modal dialogs exit by setting dialog result } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- /* */ namespace System.Windows.Forms { using System.Runtime.Serialization.Formatters; using System.Text; using System.Threading; using System.Configuration.Assemblies; using System.Runtime.InteropServices; using System.Runtime.Remoting; using System.Runtime.ConstrainedExecution; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System; using System.IO; using Microsoft.Win32; using System.Security; using System.Security.Policy; using System.Security.Permissions; using System.Collections; using System.Globalization; using System.Runtime.Versioning; using System.Reflection; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; using System.Windows.Forms.Layout; using System.Windows.Forms.VisualStyles; using File=System.IO.File; using Directory=System.IO.Directory; using System.Deployment.Internal.Isolation; ////// /// public sealed class Application { ///Provides ////// methods and properties /// to manage an application, such as methods to run and quit an application, /// to process Windows messages, and properties to get information about an application. This /// class cannot be inherited. /// /// Hash table for our event list /// static EventHandlerList eventHandlers; static string startupPath; static string executablePath; static object appFileVersion; static Type mainType; static string companyName; static string productName; static string productVersion; static string safeTopLevelCaptionSuffix; static bool useVisualStyles = false; static FormCollection forms = null; private static object internalSyncObject = new object(); static bool useWaitCursor = false; private static bool useEverettThreadAffinity = false; private static bool checkedThreadAffinity = false; private const string everettThreadAffinityValue = "EnableSystemEventsThreadAffinityCompatibility"; ////// /// in case Application.exit gets called recursively /// private static bool exiting; ////// /// Events the user can hook into /// private static readonly object EVENT_APPLICATIONEXIT = new object(); private static readonly object EVENT_THREADEXIT = new object(); // Constant string used in Application.Restart() private const string IEEXEC = "ieexec.exe"; // Constant string used for accessing ClickOnce app's data directory private const string CLICKONCE_APPS_DATADIRECTORY = "DataDirectory"; // Defines a new callback delegate type [EditorBrowsable(EditorBrowsableState.Advanced)] public delegate bool MessageLoopCallback(); ////// /// This class is static, there is no need to ever create it. /// private Application() { } ////// /// public static bool AllowQuit { get { return ThreadContext.FromCurrent().GetAllowQuit(); } } ////// Determines if the caller should be allowed to quit the application. This will return false, /// for example, if being called from a windows forms control being hosted within a web browser. The /// windows forms control should not attempt to quit the application. /// /// ////// internal static bool CanContinueIdle { get { return ThreadContext.FromCurrent().ComponentManager.FContinueIdle(); } } /// Typically, you shouldn't need to use this directly - use RenderWithVisualStyles instead. internal static bool ComCtlSupportsVisualStyles { [ResourceExposure(ResourceScope.None)] get { if (useVisualStyles && OSFeature.Feature.IsPresent(OSFeature.Themes)) { //NOTE: At this point, we may not have loaded ComCtl6 yet, but it will eventually // be loaded, so we return true here. This works because UseVisualStyles, once // set, cannot be turned off. If that changes (unlikely), this may not work. return true; } //to see if we are comctl6, we look for a function that is exposed only from comctl6 // we do not call DllGetVersion or any direct p/invoke, because the binding will be // cached. // The GetModuleHandle function returns a handle to a mapped module without incrementing its reference count. IntPtr hModule = UnsafeNativeMethods.GetModuleHandle(ExternDll.Comctl32); if (hModule != IntPtr.Zero) { try { IntPtr pFunc = UnsafeNativeMethods.GetProcAddress(new HandleRef(null, hModule), "ImageList_WriteEx"); return (pFunc != IntPtr.Zero); } catch { } } else { // Load comctl since GetModuleHandle failed to find it hModule = UnsafeNativeMethods.LoadLibrary(ExternDll.Comctl32); if (hModule != IntPtr.Zero) { try { IntPtr pFunc = UnsafeNativeMethods.GetProcAddress(new HandleRef(null, hModule), "ImageList_WriteEx"); return (pFunc != IntPtr.Zero); } finally { UnsafeNativeMethods.FreeLibrary(new HandleRef(null, hModule)); } } } return false; } } ///Returns True if it is OK to continue idle processing. Typically called in an Application.Idle event handler. ////// /// public static RegistryKey CommonAppDataRegistry { get { return Registry.LocalMachine.CreateSubKey(CommonAppDataRegistryKeyName); } } internal static string CommonAppDataRegistryKeyName { get { string template = @"Software\{0}\{1}\{2}"; return string.Format(CultureInfo.CurrentCulture, template, CompanyName, ProductName, ProductVersion); } } internal static bool UseEverettThreadAffinity { get { if (!checkedThreadAffinity) { checkedThreadAffinity = true; try { //We need access to be able to read from the registry here. We're not creating a //registry key, nor are we returning information from the registry to the user. new RegistryPermission(PermissionState.Unrestricted).Assert(); RegistryKey key = Registry.LocalMachine.OpenSubKey(CommonAppDataRegistryKeyName); if (key != null) { object value = key.GetValue(everettThreadAffinityValue); if (value != null && (int)value != 0) { useEverettThreadAffinity = true; } } } catch (SecurityException) { // Can't read the key: use default value (false) } catch (InvalidCastException) { // Key is of wrong type: use default value (false) } } return useEverettThreadAffinity; } } ///Gets the registry /// key for the application data that is shared among all users. ////// /// public static string CommonAppDataPath { // NOTE : Don't obsolete these. GetDataPath isn't on SystemInformation, and it // : provides the Win2K logo required adornments to the directory (Company\Product\Version) // get { try { if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed) { string data = AppDomain.CurrentDomain.GetData(CLICKONCE_APPS_DATADIRECTORY) as string; if (data != null) { return data; } } } catch (Exception ex) { if (ClientUtils.IsSecurityOrCriticalException(ex)) { throw; } } return GetDataPath(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)); } } ///Gets the path for the application data that is shared among all users. ////// /// public static string CompanyName { get { lock(internalSyncObject) { if (companyName == null) { // custom attribute // Assembly entryAssembly = Assembly.GetEntryAssembly(); if (entryAssembly != null) { object[] attrs = entryAssembly.GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); if (attrs != null && attrs.Length > 0) { companyName = ((AssemblyCompanyAttribute)attrs[0]).Company; } } // win32 version // if (companyName == null || companyName.Length == 0) { companyName = GetAppFileVersionInfo().CompanyName; if (companyName != null) { companyName = companyName.Trim(); } } // fake it with a namespace // won't work with MC++ see GetAppMainType. if (companyName == null || companyName.Length == 0) { Type t = GetAppMainType(); if (t != null) { string ns = t.Namespace; if (!string.IsNullOrEmpty(ns)){ int firstDot = ns.IndexOf("."); if( firstDot != -1 ){ companyName = ns.Substring(0, firstDot); } else{ companyName = ns; } } else { // last ditch... no namespace, use product name... // companyName = ProductName; } } } } } return companyName; } } ///Gets the company name associated with the application. ////// /// public static CultureInfo CurrentCulture { get { return Thread.CurrentThread.CurrentCulture; } set { Thread.CurrentThread.CurrentCulture = value; } } ///Gets /// or sets the locale information for the current thread. ////// /// public static InputLanguage CurrentInputLanguage { get { return InputLanguage.CurrentInputLanguage; } set { Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "AffectThreadBehavior Demanded"); IntSecurity.AffectThreadBehavior.Demand(); InputLanguage.CurrentInputLanguage = value; } } internal static bool CustomThreadExceptionHandlerAttached { get { return ThreadContext.FromCurrent().CustomThreadExceptionHandlerAttached; } } ///Gets or /// sets the current input language for the current thread. ////// /// /// SECREVIEW ReviewImperitiveSecurity: /// vulnerability to watch out for: A method uses imperative security and might be constructing the permission using state information or return values that can change while the demand is active. /// reason for exclude: the return value of GetModuleFileName shouldnt change between when we called it and when we demanded permissions. [SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")] public static string ExecutablePath { get { if (executablePath == null) { Assembly asm = Assembly.GetEntryAssembly(); if (asm == null) { StringBuilder sb = new StringBuilder(NativeMethods.MAX_PATH); UnsafeNativeMethods.GetModuleFileName(NativeMethods.NullHandleRef, sb, sb.Capacity); executablePath = IntSecurity.UnsafeGetFullPath(sb.ToString()); } else { String ecb = asm.EscapedCodeBase; Uri codeBase = new Uri(ecb); if (codeBase.Scheme == "file") { executablePath = NativeMethods.GetLocalPath(ecb); } else { executablePath = codeBase.ToString(); } } } Uri exeUri = new Uri(executablePath); if (exeUri.Scheme == "file") { Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "FileIO(" + executablePath + ") Demanded"); new FileIOPermission(FileIOPermissionAccess.PathDiscovery, executablePath).Demand(); } return executablePath; } } ////// Gets the /// path for the executable file that started the application. /// ////// /// public static string LocalUserAppDataPath { // NOTE : Don't obsolete these. GetDataPath isn't on SystemInformation, and it // : provides the Win2K logo required adornments to the directory (Company\Product\Version) // get { try { if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed) { string data = AppDomain.CurrentDomain.GetData(CLICKONCE_APPS_DATADIRECTORY) as string; if (data != null) { return data; } } } catch (Exception ex) { if (ClientUtils.IsSecurityOrCriticalException(ex)) { throw; } } return GetDataPath(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)); } } ///Gets the path for the application data specific to a local, non-roaming user. ////// /// public static bool MessageLoop { get { return ThreadContext.FromCurrent().GetMessageLoop(); } } ////// Determines if a message loop exists on this thread. /// ////// /// public static FormCollection OpenForms { [UIPermission(SecurityAction.Demand, Window=UIPermissionWindow.AllWindows)] get { return OpenFormsInternal; } } ////// Gets the forms collection associated with this application. /// ////// internal static FormCollection OpenFormsInternal { get { if (forms == null) { forms = new FormCollection(); } return forms; } } ////// Internal version of OpenForms without the security demand. /// ////// internal static void OpenFormsInternalAdd(Form form) { OpenFormsInternal.Add(form); } ////// Thread safe addition of form to the OpenForms collection. /// ////// internal static void OpenFormsInternalRemove(Form form) { OpenFormsInternal.Remove(form); } ////// Thread safe removal of form from the OpenForms collection. /// ////// /// public static string ProductName { get { lock(internalSyncObject) { if (productName == null) { // custom attribute // Assembly entryAssembly = Assembly.GetEntryAssembly(); if (entryAssembly != null) { object[] attrs = entryAssembly.GetCustomAttributes(typeof(AssemblyProductAttribute), false); if (attrs != null && attrs.Length > 0) { productName = ((AssemblyProductAttribute)attrs[0]).Product; } } // win32 version info // if (productName == null || productName.Length == 0) { productName = GetAppFileVersionInfo().ProductName; if (productName != null) { productName = productName.Trim(); } } // fake it with namespace // won't work with MC++ see GetAppMainType. if (productName == null || productName.Length == 0) { Type t = GetAppMainType(); if (t != null) { string ns = t.Namespace; if (!string.IsNullOrEmpty(ns)) { int lastDot = ns.LastIndexOf("."); if (lastDot != -1 && lastDot < ns.Length - 1) { productName = ns.Substring(lastDot+1); } else { productName = ns; } } else{ // last ditch... use the main type // productName = t.Name; } } } } } return productName; } } ////// Gets /// the product name associated with this application. /// ////// /// public static string ProductVersion { get { lock(internalSyncObject) { if (productVersion == null) { // custom attribute // Assembly entryAssembly = Assembly.GetEntryAssembly(); if (entryAssembly != null) { object[] attrs = entryAssembly.GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false); if (attrs != null && attrs.Length > 0) { productVersion = ((AssemblyInformationalVersionAttribute)attrs[0]).InformationalVersion; } } // win32 version info // if (productVersion == null || productVersion.Length == 0) { productVersion = GetAppFileVersionInfo().ProductVersion; if (productVersion != null) { productVersion = productVersion.Trim(); } } // fake it // if (productVersion == null || productVersion.Length == 0) { productVersion = "1.0.0.0"; } } } return productVersion; } } // Allows the hosting environment to register a callback [ EditorBrowsable(EditorBrowsableState.Advanced), SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode) ] public static void RegisterMessageLoop(MessageLoopCallback callback) { ThreadContext.FromCurrent().RegisterMessageLoop(callback); } ////// Gets /// the product version associated with this application. /// ////// /// Magic property that answers a simple question - are my controls currently going to render with // visual styles? If you are doing visual styles rendering, use this to be consistent with the rest // of the controls in your app. /// public static bool RenderWithVisualStyles { get { return (ComCtlSupportsVisualStyles && VisualStyles.VisualStyleRenderer.IsSupported); } } ////// /// public static string SafeTopLevelCaptionFormat { get { if (safeTopLevelCaptionSuffix == null) { safeTopLevelCaptionSuffix = SR.GetString(SR.SafeTopLevelCaptionFormat); // 0 - original, 1 - zone, 2 - site } return safeTopLevelCaptionSuffix; } set { Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "WindowAdornmentModification Demanded"); IntSecurity.WindowAdornmentModification.Demand(); if (value == null) value = string.Empty; safeTopLevelCaptionSuffix = value; } } ///Gets or sets the format string to apply to top level window captions /// when they are displayed with a warning banner. ////// /// /// SECREVIEW ReviewImperitiveSecurity: /// vulnerability to watch out for: A method uses imperative security and might be constructing the permission using state information or return values that can change while the demand is active. /// reason for exclude: the return value of GetModuleFileName shouldnt change between when we called it and when we demanded permissions. [SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")] public static string StartupPath { get { if (startupPath == null) { StringBuilder sb = new StringBuilder(NativeMethods.MAX_PATH); UnsafeNativeMethods.GetModuleFileName(NativeMethods.NullHandleRef, sb, sb.Capacity); startupPath = Path.GetDirectoryName(sb.ToString()); } Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "FileIO(" + startupPath + ") Demanded"); new FileIOPermission(FileIOPermissionAccess.PathDiscovery, startupPath).Demand(); return startupPath; } } // Allows the hosting environment to unregister a callback [ EditorBrowsable(EditorBrowsableState.Advanced), SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode) ] public static void UnregisterMessageLoop() { ThreadContext.FromCurrent().RegisterMessageLoop(null); } ////// Gets the /// path for the executable file that started the application. /// ////// /// public static bool UseWaitCursor { get { return useWaitCursor; } set { lock (FormCollection.CollectionSyncRoot) { useWaitCursor = value; // Set the WaitCursor of all forms. foreach (Form f in OpenFormsInternal) { f.UseWaitCursor = useWaitCursor; } } } } ///Gets /// or sets whether the wait cursor is used for all open forms of the application. ////// /// public static string UserAppDataPath { // NOTE : Don't obsolete these. GetDataPath isn't on SystemInformation, and it // : provides the Win2K logo required adornments to the directory (Company\Product\Version) // get { try { if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed) { string data = AppDomain.CurrentDomain.GetData(CLICKONCE_APPS_DATADIRECTORY) as string; if (data != null) { return data; } } } catch (Exception ex) { if (ClientUtils.IsSecurityOrCriticalException(ex)) { throw; } } return GetDataPath(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)); } } ///Gets the path for the application data specific to the roaming user. ////// /// public static RegistryKey UserAppDataRegistry { get { string template = @"Software\{0}\{1}\{2}"; return Registry.CurrentUser.CreateSubKey(string.Format(CultureInfo.CurrentCulture, template, CompanyName, ProductName, ProductVersion)); } } internal static bool UseVisualStyles { get { return useVisualStyles; } } internal static string WindowsFormsVersion { get { return "WindowsForms10"; } } internal static string WindowMessagesVersion { get { return "WindowsForms12"; } } ///Gets the registry key of /// the application data specific to the roaming user. ////// /// public static VisualStyleState VisualStyleState { get { if (!VisualStyleInformation.IsSupportedByOS) { return VisualStyleState.NoneEnabled; } VisualStyleState vState = (VisualStyleState) SafeNativeMethods.GetThemeAppProperties(); return vState; } set { if (VisualStyleInformation.IsSupportedByOS) { if (!ClientUtils.IsEnumValid(value, (int)value, (int)VisualStyleState.NoneEnabled, (int)VisualStyleState.ClientAndNonClientAreasEnabled)) { throw new InvalidEnumArgumentException("value", (int)value, typeof(VisualStyleState)); } SafeNativeMethods.SetThemeAppProperties((int)value); //248887 we need to send a WM_THEMECHANGED to the top level windows of this application. //We do it this way to ensure that we get all top level windows -- whether we created them or not. SafeNativeMethods.EnumThreadWindowsCallback callback = new SafeNativeMethods.EnumThreadWindowsCallback(Application.SendThemeChanged); SafeNativeMethods.EnumWindows(callback, IntPtr.Zero); GC.KeepAlive(callback); } } } ////// Use this property to determine how visual styles will be applied to this application. /// This property is meaningful only if visual styles are supported on the current /// platform (VisualStyleInformation.SupportedByOS is true). /// /// This property can be set only to one of the S.W.F.VisualStyles.VisualStyleState enum values. /// ////// This helper broadcasts out a WM_THEMECHANGED to appropriate top level windows of this app. /// private static bool SendThemeChanged(IntPtr handle, IntPtr extraParameter) { int processId; int thisPID = SafeNativeMethods.GetCurrentProcessId(); SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(null, handle), out processId); if (processId == thisPID && SafeNativeMethods.IsWindowVisible(new HandleRef(null, handle))) { SendThemeChangedRecursive(handle, IntPtr.Zero); SafeNativeMethods.RedrawWindow(new HandleRef(null, handle), null, NativeMethods.NullHandleRef, NativeMethods.RDW_INVALIDATE | NativeMethods.RDW_FRAME | NativeMethods.RDW_ERASE | NativeMethods.RDW_ALLCHILDREN); } return true; } ////// This helper broadcasts out a WM_THEMECHANGED this window and all children. /// it is assumed at this point that the handle belongs to the current process and has a visible top level window. /// private static bool SendThemeChangedRecursive(IntPtr handle, IntPtr lparam) { //first send to all children... UnsafeNativeMethods.EnumChildWindows(new HandleRef(null, handle), new NativeMethods.EnumChildrenCallback(Application.SendThemeChangedRecursive), NativeMethods.NullHandleRef); //then do myself. UnsafeNativeMethods.SendMessage(new HandleRef(null, handle), NativeMethods.WM_THEMECHANGED, 0, 0); return true; } ////// /// public static event EventHandler ApplicationExit { add { AddEventHandler(EVENT_APPLICATIONEXIT, value); } remove { RemoveEventHandler(EVENT_APPLICATIONEXIT, value); } } private static void AddEventHandler(object key, Delegate value) { lock(internalSyncObject) { if (null == eventHandlers) { eventHandlers = new EventHandlerList(); } eventHandlers.AddHandler(key, value); } } private static void RemoveEventHandler(object key, Delegate value) { lock(internalSyncObject) { if (null == eventHandlers) { return; } eventHandlers.RemoveHandler(key, value); } } ///Occurs when the application is about to shut down. ////// /// public static void AddMessageFilter(IMessageFilter value) { Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "ManipulateWndProcAndHandles Demanded"); IntSecurity.UnmanagedCode.Demand(); ThreadContext.FromCurrent().AddMessageFilter(value); } ///Adds a message filter to monitor Windows messages as they are routed to their /// destinations. ////// Processes all message filters for given message /// [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode), EditorBrowsable(EditorBrowsableState.Advanced), SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference") // using ref is OK. ] public static bool FilterMessage(ref Message message) { bool modified; // Create copy of MSG structure NativeMethods.MSG msg = new NativeMethods.MSG(); msg.hwnd = message.HWnd; msg.message = message.Msg; msg.wParam = message.WParam; msg.lParam = message.LParam; bool processed = ThreadContext.FromCurrent().ProcessFilters(ref msg, out modified); if (modified) { message.HWnd = msg.hwnd; message.Msg = msg.message; message.WParam = msg.wParam; message.LParam = msg.lParam; } return processed; } ////// /// public static event EventHandler Idle { add { ThreadContext current = ThreadContext.FromCurrent(); lock(current) { current.idleHandler += value; // This just ensures that the component manager is hooked up. We // need it for idle time processing. // object o = current.ComponentManager; } } remove { ThreadContext current = ThreadContext.FromCurrent(); lock(current) { current.idleHandler -= value; } } } ////// Occurs when the application has finished processing and is about to enter the /// idle state. /// ////// /// [EditorBrowsable(EditorBrowsableState.Advanced)] public static event EventHandler EnterThreadModal { [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] add { ThreadContext current = ThreadContext.FromCurrent(); lock(current) { current.enterModalHandler += value; } } [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] remove { ThreadContext current = ThreadContext.FromCurrent(); lock(current) { current.enterModalHandler -= value; } } } ////// Occurs when the application is about to enter a modal state /// ////// /// [EditorBrowsable(EditorBrowsableState.Advanced)] public static event EventHandler LeaveThreadModal { [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] add { ThreadContext current = ThreadContext.FromCurrent(); lock(current) { current.leaveModalHandler += value; } } [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] remove { ThreadContext current = ThreadContext.FromCurrent(); lock(current) { current.leaveModalHandler -= value; } } } ////// Occurs when the application is about to leave a modal state /// ////// /// public static event ThreadExceptionEventHandler ThreadException { add { Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "AffectThreadBehavior Demanded"); IntSecurity.AffectThreadBehavior.Demand(); ThreadContext current = ThreadContext.FromCurrent(); lock(current) { current.threadExceptionHandler = value; } } remove { ThreadContext current = ThreadContext.FromCurrent(); lock(current) { current.threadExceptionHandler -= value; } } } ///Occurs when an untrapped thread exception is thrown. ////// /// public static event EventHandler ThreadExit { add { AddEventHandler(EVENT_THREADEXIT, value); } remove { RemoveEventHandler(EVENT_THREADEXIT, value); } } ///Occurs when a thread is about to shut down. When /// the main thread for an application is about to be shut down, /// this event will be raised first, followed by an ApplicationExit /// event. ////// /// Called immediately before we begin pumping messages for a modal message loop. /// Does not actually start a message pump; that's the caller's responsibility. /// ///internal static void BeginModalMessageLoop() { ThreadContext.FromCurrent().BeginModalMessageLoop(null); } /// /// /// public static void DoEvents() { ThreadContext.FromCurrent().RunMessageLoop(NativeMethods.MSOCM.msoloopDoEvents, null); } ///Processes /// all Windows messages currently in the message queue. ////// internal static void DoEventsModal() { ThreadContext.FromCurrent().RunMessageLoop(NativeMethods.MSOCM.msoloopDoEventsModal, null); } ////// /// public static void EnableVisualStyles() { string assemblyLoc = null; // SECREVIEW : This Assert is ok, getting the module path is a safe operation, // the result is provided by the system. // FileIOPermission fiop = new FileIOPermission(PermissionState.None); fiop.AllFiles = FileIOPermissionAccess.PathDiscovery; fiop.Assert(); try { assemblyLoc = typeof(Application).Assembly.Location; } finally { CodeAccessPermission.RevertAssert(); } // Pull manifest from our resources if (assemblyLoc != null) { EnableVisualStylesInternal(assemblyLoc, 101); } } ////// Enables visual styles for all subsequent Application.Run() and CreateHandle() calls. /// Uses the default theming manifest file shipped with the redist. /// ////// Internal version ***WITHOUT SECURITY DEMAND***. /// private static void EnableVisualStylesInternal(string assemblyFileName, int nativeResourceID) { //Note that if the following call fails, we don't throw an exception. //Theming scope won't work, thats all. useVisualStyles = UnsafeNativeMethods.ThemingScope.CreateActivationContext(assemblyFileName, nativeResourceID); } ////// /// Called immediately after we stop pumping messages for a modal message loop. /// Does not actually end the message pump itself. /// ///internal static void EndModalMessageLoop() { ThreadContext.FromCurrent().EndModalMessageLoop(null); } /// /// /// public static void Exit() { Exit(null); } ///Overload of Exit that does not care about e.Cancel. ////// /// [ EditorBrowsable(EditorBrowsableState.Advanced), SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers") ] public static void Exit(CancelEventArgs e) { Assembly entryAssembly = Assembly.GetEntryAssembly(); Assembly callingAssembly = Assembly.GetCallingAssembly(); if (entryAssembly == null || callingAssembly == null || !entryAssembly.Equals(callingAssembly)) { Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "AffectThreadBehavior Demanded"); IntSecurity.AffectThreadBehavior.Demand(); } bool cancelExit = ExitInternal(); if (e != null) { e.Cancel = cancelExit; } } ///Informs all message pumps that they are to terminate and /// then closes all application windows after the messages have been processed. /// e.Cancel indicates whether any of the open forms cancelled the exit call. ////// private static bool ExitInternal() { bool cancelExit = false; lock (internalSyncObject) { if (exiting) { return false; } exiting = true; try { // Raise the FormClosing and FormClosed events for each open form if (forms != null) { foreach (Form f in OpenFormsInternal) { if (f.RaiseFormClosingOnAppExit()) { cancelExit = true; break; // quit the loop as soon as one form refuses to close } } } if (!cancelExit) { if (forms != null) { while (OpenFormsInternal.Count > 0) { OpenFormsInternal[0].RaiseFormClosedOnAppExit(); // OnFormClosed removes the form from the FormCollection } } ThreadContext.ExitApplication(); } } finally { exiting = false; } } return cancelExit; } ///Private version of Exit which does not do any security checks. ////// /// public static void ExitThread() { Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "AffectThreadBehavior Demanded"); IntSecurity.AffectThreadBehavior.Demand(); ExitThreadInternal(); } private static void ExitThreadInternal() { ThreadContext context = ThreadContext.FromCurrent(); if (context.ApplicationContext != null) { context.ApplicationContext.ExitThread(); } else { context.Dispose(true); } } // When a Form receives a WM_ACTIVATE message, it calls this method so we can do the // appropriate MsoComponentManager activation magic internal static void FormActivated(bool modal, bool activated) { if (modal) { return; } ThreadContext.FromCurrent().FormActivated(activated); } ///Exits the message loop on the /// current thread and closes all windows on the thread. ////// /// Retrieves the FileVersionInfo associated with the main module for /// the application. /// private static FileVersionInfo GetAppFileVersionInfo() { lock (internalSyncObject) { if (appFileVersion == null) { Type t = GetAppMainType(); if (t != null) { // SECREVIEW : This Assert is ok, getting the module's version is a safe operation, // the result is provided by the system. // FileIOPermission fiop = new FileIOPermission( PermissionState.None ); fiop.AllFiles = FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read; fiop.Assert(); try { appFileVersion = FileVersionInfo.GetVersionInfo(t.Module.FullyQualifiedName); } finally { CodeAccessPermission.RevertAssert(); } } else { appFileVersion = FileVersionInfo.GetVersionInfo(ExecutablePath); } } } return(FileVersionInfo)appFileVersion; } ////// /// Retrieves the Type that contains the "Main" method. /// private static Type GetAppMainType() { lock(internalSyncObject) { if (mainType == null) { Assembly exe = Assembly.GetEntryAssembly(); // Get Main type...This doesn't work in MC++ because Main is a global function and not // a class static method (it doesn't belong to a Type). if (exe != null) { mainType = exe.EntryPoint.ReflectedType; } } } return mainType; } ////// Locates a thread context given a window handle. /// private static ThreadContext GetContextForHandle(HandleRef handle) { int pid; int id = SafeNativeMethods.GetWindowThreadProcessId(handle, out pid); ThreadContext cxt = ThreadContext.FromId(id); Debug.Assert(cxt != null, "No thread context for handle. This is expected if you saw a previous assert about the handle being invalid."); return cxt; } ////// /// Returns a string that is the combination of the /// basePath + CompanyName + ProducName + ProductVersion. This /// will also create the directory if it doesn't exist. /// private static string GetDataPath(String basePath) { string template = @"{0}\{1}\{2}\{3}"; string company = CompanyName; string product = ProductName; string version = ProductVersion; string path = string.Format(CultureInfo.CurrentCulture, template, new object[] {basePath, company, product, version}); lock(internalSyncObject) { if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } } return path; } ////// /// Called by the last thread context before it shuts down. /// private static void RaiseExit() { if (eventHandlers != null) { Delegate exit = eventHandlers[EVENT_APPLICATIONEXIT]; if (exit != null) ((EventHandler)exit)(null, EventArgs.Empty); } } ////// /// Called by the each thread context before it shuts down. /// private static void RaiseThreadExit() { if (eventHandlers != null) { Delegate exit = eventHandlers[EVENT_THREADEXIT]; if (exit != null) { ((EventHandler)exit)(null, EventArgs.Empty); } } } ////// /// /// "Parks" the given HWND to a temporary HWND. This allows WS_CHILD windows to /// be parked. /// internal static void ParkHandle(HandleRef handle) { Debug.Assert(UnsafeNativeMethods.IsWindow(handle), "Handle being parked is not a valid window handle"); Debug.Assert(((int)UnsafeNativeMethods.GetWindowLong(handle, NativeMethods.GWL_STYLE) & NativeMethods.WS_CHILD) != 0, "Only WS_CHILD windows should be parked."); ThreadContext cxt = GetContextForHandle(handle); if (cxt != null) { cxt.ParkingWindow.ParkHandle(handle); } } ////// /// /// "Parks" the given HWND to a temporary HWND. This allows WS_CHILD windows to /// be parked. /// internal static void ParkHandle(CreateParams cp) { ThreadContext cxt = ThreadContext.FromCurrent(); if (cxt != null) { cp.Parent = cxt.ParkingWindow.Handle; } } ////// /// public static System.Threading.ApartmentState OleRequired() { return ThreadContext.FromCurrent().OleRequired(); } ////// Initializes OLE on the current thread. /// ////// /// public static void OnThreadException(Exception t) { ThreadContext.FromCurrent().OnThreadException(t); } ///Raises the ///event. /// /// /// "Unparks" the given HWND to a temporary HWND. This allows WS_CHILD windows to /// be parked. /// internal static void UnparkHandle(HandleRef handle) { ThreadContext cxt = GetContextForHandle(handle); if (cxt != null) { cxt.ParkingWindow.UnparkHandle(handle); } } ////// /// Raises the Idle event. /// [ EditorBrowsable(EditorBrowsableState.Advanced), SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode), SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers"), SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate") ] public static void RaiseIdle(EventArgs e) { ThreadContext current = ThreadContext.FromCurrent(); if (current.idleHandler != null) { current.idleHandler(Thread.CurrentThread, e); } } ////// /// public static void RemoveMessageFilter(IMessageFilter value) { ThreadContext.FromCurrent().RemoveMessageFilter(value); } ///Removes a message /// filter from the application's message pump. ////// /// [ SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode), SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode) ] public static void Restart() { if (Assembly.GetEntryAssembly() == null) { throw new NotSupportedException(SR.GetString(SR.RestartNotSupported)); } bool hrefExeCase = false; Process process = Process.GetCurrentProcess(); Debug.Assert(process != null); if (String.Equals(process.MainModule.ModuleName, IEEXEC, StringComparison.OrdinalIgnoreCase)) { string clrPath = string.Empty; // SECREVIEW : This Assert is ok, getting the module path is a safe operation, // the result is provided by the system. // new FileIOPermission(PermissionState.Unrestricted).Assert(); try { clrPath = Path.GetDirectoryName(typeof(object).Module.FullyQualifiedName); } finally { CodeAccessPermission.RevertAssert(); } if (String.Equals(clrPath + "\\" + IEEXEC, process.MainModule.FileName, StringComparison.OrdinalIgnoreCase)) { // HRef exe case hrefExeCase = true; ExitInternal(); string launchUrl = AppDomain.CurrentDomain.GetData("APP_LAUNCH_URL") as string; if (launchUrl != null) { Process.Start(process.MainModule.FileName, launchUrl); } } } if (!hrefExeCase) { if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed) { // ClickOnce app case string appFullName = System.Deployment.Application.ApplicationDeployment.CurrentDeployment.UpdatedApplicationFullName; UInt32 hostType = (UInt32) Application.ClickOnceUtility.GetHostTypeFromMetaData(appFullName); ExitInternal(); UnsafeNativeMethods.CorLaunchApplication(hostType, appFullName, 0, null, 0, null, new UnsafeNativeMethods.PROCESS_INFORMATION()); } else { // Regular app case String[] arguments = Environment.GetCommandLineArgs(); Debug.Assert(arguments != null && arguments.Length > 0); StringBuilder sb = new StringBuilder((arguments.Length - 1) * 16); for (int argumentIndex = 1; argumentIndex < arguments.Length - 1; argumentIndex++) { sb.Append('"'); sb.Append(arguments[argumentIndex]); sb.Append("\" "); } if (arguments.Length > 1) { sb.Append('"'); sb.Append(arguments[arguments.Length - 1]); sb.Append('"'); } ProcessStartInfo currentStartInfo = Process.GetCurrentProcess().StartInfo; currentStartInfo.FileName = Application.ExecutablePath; // [....]: use this according to spec. // String executable = Assembly.GetEntryAssembly().CodeBase; // Debug.Assert(executable != null); if (sb.Length > 0) { currentStartInfo.Arguments = sb.ToString(); } ExitInternal(); Process.Start(currentStartInfo); } } } ///Restarts the application. ////// /// public static void Run() { ThreadContext.FromCurrent().RunMessageLoop(NativeMethods.MSOCM.msoloopMain, new ApplicationContext()); } ///Begins running a /// standard /// application message loop on the current thread, /// without a form. ////// /// public static void Run(Form mainForm) { ThreadContext.FromCurrent().RunMessageLoop(NativeMethods.MSOCM.msoloopMain, new ApplicationContext(mainForm)); } ///Begins running a standard application message loop on the current /// thread, and makes the specified form visible. ////// /// public static void Run(ApplicationContext context) { ThreadContext.FromCurrent().RunMessageLoop(NativeMethods.MSOCM.msoloopMain, context); } ///Begins running a /// standard /// application message loop on the current thread, /// without a form. ////// /// Runs a modal dialog. This starts a special type of message loop that runs until /// the dialog has a valid DialogResult. This is called internally by a form /// when an application calls System.Windows.Forms.Form.ShowDialog(). /// ///internal static void RunDialog(Form form) { ThreadContext.FromCurrent().RunMessageLoop(NativeMethods.MSOCM.msoloopModalForm, new ModalApplicationContext(form)); } /// /// /// Sets the static UseCompatibleTextRenderingDefault field on Control to the value passed in. /// This switch determines the default text rendering engine to use by some controls that support /// switching rendering engine. /// [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] public static void SetCompatibleTextRenderingDefault(bool defaultValue) { if (NativeWindow.AnyHandleCreated) { throw new InvalidOperationException(SR.GetString(SR.Win32WindowAlreadyCreated)); } Control.UseCompatibleTextRenderingDefault = defaultValue; } ////// /// Sets the suspend/hibernate state of the machine. /// Returns true if the call succeeded, else false. /// public static bool SetSuspendState(PowerState state, bool force, bool disableWakeEvent) { IntSecurity.AffectMachineState.Demand(); return UnsafeNativeMethods.SetSuspendState(state == PowerState.Hibernate, force, disableWakeEvent); } ////// Overload version of SetUnhandledExceptionMode that sets the UnhandledExceptionMode /// mode at the current thread level. /// public static void SetUnhandledExceptionMode(UnhandledExceptionMode mode) { SetUnhandledExceptionMode(mode, true /*threadScope*/); } ////// This method can be used to modify the exception handling behavior of /// NativeWindow. By default, NativeWindow will detect if an application /// is running under a debugger, or is running on a machine with a debugger /// installed. In this case, an unhandled exception in the NativeWindow's /// WndProc method will remain unhandled so the debugger can trap it. If /// there is no debugger installed NativeWindow will trap the exception /// and route it to the Application class's unhandled exception filter. /// /// You can control this behavior via a config file, or directly through /// code using this method. Setting the unhandled exception mode does /// not change the behavior of any NativeWindow objects that are currently /// connected to window handles; it only affects new handle connections. /// /// The parameter threadScope defines the scope of the setting: either /// the current thread or the application. /// When a thread exception mode isn't UnhandledExceptionMode.Automatic, it takes /// precedence over the application exception mode. /// public static void SetUnhandledExceptionMode(UnhandledExceptionMode mode, bool threadScope) { Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "AffectThreadBehavior Demanded"); IntSecurity.AffectThreadBehavior.Demand(); NativeWindow.SetUnhandledExceptionModeInternal(mode, threadScope); } // Exposes GetHostTypeFromMetaData provided by the ClickOnce team. // Used to restart ClickOnce applications in Application.Restart(). private class ClickOnceUtility { public enum HostType { Default = 0x0, AppLaunch = 0x1, CorFlag = 0x2 } private ClickOnceUtility() { } public static HostType GetHostTypeFromMetaData(string appFullName) { HostType ht = HostType.Default; try { // Convert into IDefinitionAppId. IDefinitionAppId defAppId = IsolationInterop.AppIdAuthority.TextToDefinition(0, appFullName); bool isFullTrust = GetPropertyBoolean(defAppId, "IsFullTrust"); ht = isFullTrust ? HostType.CorFlag : HostType.AppLaunch; } catch { // Eating exceptions. IsFullTrust metadata is not present. } return ht; } // Get metadata property as boolean. private static bool GetPropertyBoolean(IDefinitionAppId appId, string propName) { string boolStr = GetPropertyString(appId, propName); if (string.IsNullOrEmpty(boolStr)) { return false; } try { return Convert.ToBoolean(boolStr, CultureInfo.InvariantCulture); } catch { return false; } } // Get metadata property as string. private static string GetPropertyString(IDefinitionAppId appId, string propName) { // Retrieve property and convert to string. byte[] bytes = IsolationInterop.UserStore.GetDeploymentProperty(0, appId, InstallReference, new Guid("2ad613da-6fdb-4671-af9e-18ab2e4df4d8"), propName); // Check for valid Unicode string. Must end with L'\0'. int length = bytes.Length; if ((length == 0) || ((bytes.Length % 2) != 0) || (bytes[length - 2] != 0) || (bytes[length - 1] != 0)) { return null; } return Encoding.Unicode.GetString(bytes, 0, length - 2); } // Get the ClickOnce-specific constant install reference. private static StoreApplicationReference InstallReference { get { return new StoreApplicationReference( IsolationInterop.GUID_SXS_INSTALL_REFERENCE_SCHEME_OPAQUESTRING, "{3f471841-eef2-47d6-89c0-d028f03a4ad5}", null); } } } ////// /// This is our implementation of the MSO ComponentManager. The Componoent Manager is /// an object that is responsible for handling all message loop activity in a process. /// The idea is that someone in the process implements the component manager and then /// anyone who wants access to the message loop can get to it. We implement this /// so we have good interop with office and VS. The first time we need a /// component manager, we search the OLE message filter for one. If that fails, we /// create our own and install it in the message filter. /// /// This class is not used when running inside the Visual Studio shell. /// private class ComponentManager : UnsafeNativeMethods.IMsoComponentManager { // ComponentManager instance data. // private class ComponentHashtableEntry { public UnsafeNativeMethods.IMsoComponent component; public NativeMethods.MSOCRINFOSTRUCT componentInfo; } private Hashtable oleComponents; private int cookieCounter = 0; private UnsafeNativeMethods.IMsoComponent activeComponent = null; private UnsafeNativeMethods.IMsoComponent trackingComponent = null; private int currentState = 0; private Hashtable OleComponents { get { if (oleComponents == null) { oleComponents = new Hashtable(); cookieCounter = 0; } return oleComponents; } } ////// /// Return in *ppvObj an implementation of interface iid for service /// guidService (same as IServiceProvider::QueryService). /// Return NOERROR if the requested service is supported, otherwise return /// NULL in *ppvObj and an appropriate error (eg E_FAIL, E_NOINTERFACE). /// int UnsafeNativeMethods.IMsoComponentManager.QueryService( ref Guid guidService, ref Guid iid, out object ppvObj) { ppvObj = null; return NativeMethods.E_NOINTERFACE; } ////// /// Standard FDebugMessage method. /// Since IMsoComponentManager is a reference counted interface, /// MsoDWGetChkMemCounter should be used when processing the /// msodmWriteBe message. /// bool UnsafeNativeMethods.IMsoComponentManager.FDebugMessage( IntPtr hInst, int msg, IntPtr wparam, IntPtr lparam) { return true; } ////// /// Register component piComponent and its registration info pcrinfo with /// this component manager. Return in *pdwComponentID a cookie which will /// identify the component when it calls other IMsoComponentManager /// methods. /// Return TRUE if successful, FALSE otherwise. /// bool UnsafeNativeMethods.IMsoComponentManager.FRegisterComponent(UnsafeNativeMethods.IMsoComponent component, NativeMethods.MSOCRINFOSTRUCT pcrinfo, out int dwComponentID) { // Construct Hashtable entry for this component // ComponentHashtableEntry entry = new ComponentHashtableEntry(); entry.component = component; entry.componentInfo = pcrinfo; OleComponents.Add(++cookieCounter, entry); // Return the cookie // dwComponentID = cookieCounter; Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager: Component registered. ID: " + cookieCounter.ToString(CultureInfo.InvariantCulture)); return true; } ////// /// Undo the registration of the component identified by dwComponentID /// (the cookie returned from the FRegisterComponent method). /// Return TRUE if successful, FALSE otherwise. /// bool UnsafeNativeMethods.IMsoComponentManager.FRevokeComponent(int dwComponentID) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager: Revoking component " + dwComponentID.ToString(CultureInfo.InvariantCulture)); ComponentHashtableEntry entry = (ComponentHashtableEntry)OleComponents[dwComponentID]; if (entry == null) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "Compoenent not registered."); return false; } if (entry.component == activeComponent) { activeComponent = null; } if (entry.component == trackingComponent) { trackingComponent = null; } OleComponents.Remove(dwComponentID); return true; } ////// /// Update the registration info of the component identified by /// dwComponentID (the cookie returned from FRegisterComponent) with the /// new registration information pcrinfo. /// Typically this is used to update the idle time registration data, but /// can be used to update other registration data as well. /// Return TRUE if successful, FALSE otherwise. /// bool UnsafeNativeMethods.IMsoComponentManager.FUpdateComponentRegistration( int dwComponentID, NativeMethods.MSOCRINFOSTRUCT info ) { // Update the registration info // ComponentHashtableEntry entry = (ComponentHashtableEntry)OleComponents[dwComponentID]; if (entry == null) { return false; } entry.componentInfo = info; return true; } ////// /// Notify component manager that component identified by dwComponentID /// (cookie returned from FRegisterComponent) has been activated. /// The active component gets the chance to process messages before they /// are dispatched (via IMsoComponent::FPreTranslateMessage) and typically /// gets first chance at idle time after the host. /// This method fails if another component is already Exclusively Active. /// In this case, FALSE is returned and SetLastError is set to /// msoerrACompIsXActive (comp usually need not take any special action /// in this case). /// Return TRUE if successful. /// bool UnsafeNativeMethods.IMsoComponentManager.FOnComponentActivate(int dwComponentID) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager: Component activated. ID: " + dwComponentID.ToString(CultureInfo.InvariantCulture)); ComponentHashtableEntry entry = (ComponentHashtableEntry)OleComponents[dwComponentID]; if (entry == null) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "*** Component not registered ***"); return false; } Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "New active component is : " + entry.component.ToString()); activeComponent = entry.component; return true; } ////// /// Called to inform component manager that component identified by /// dwComponentID (cookie returned from FRegisterComponent) wishes /// to perform a tracking operation (such as mouse tracking). /// The component calls this method with fTrack == TRUE to begin the /// tracking operation and with fTrack == FALSE to end the operation. /// During the tracking operation the component manager routes messages /// to the tracking component (via IMsoComponent::FPreTranslateMessage) /// rather than to the active component. When the tracking operation ends, /// the component manager should resume routing messages to the active /// component. /// Note: component manager should perform no idle time processing during a /// tracking operation other than give the tracking component idle /// time via IMsoComponent::FDoIdle. /// Note: there can only be one tracking component at a time. /// Return TRUE if successful, FALSE otherwise. /// bool UnsafeNativeMethods.IMsoComponentManager.FSetTrackingComponent(int dwComponentID, bool fTrack) { ComponentHashtableEntry entry = (ComponentHashtableEntry)OleComponents[dwComponentID]; if (entry == null) { return false; } if (entry.component == trackingComponent ^ fTrack) { return false; } if (fTrack) { trackingComponent = entry.component; } else { trackingComponent = null; } return true; } ////// /// Notify component manager that component identified by dwComponentID /// (cookie returned from FRegisterComponent) is entering the state /// identified by uStateID (msocstateXXX value). (For convenience when /// dealing with sub CompMgrs, the host can call this method passing 0 for /// dwComponentID.) /// Component manager should notify all other interested components within /// the state context indicated by uContext (a msoccontextXXX value), /// excluding those within the state context of a CompMgr in rgpicmExclude, /// via IMsoComponent::OnEnterState (see "Comments on State Contexts", /// above). /// Component Manager should also take appropriate action depending on the /// value of uStateID (see msocstate comments, above). /// dwReserved is reserved for future use and should be zero. /// /// rgpicmExclude (can be NULL) is an array of cpicmExclude CompMgrs (can /// include root CompMgr and/or sub CompMgrs); components within the state /// context of a CompMgr appearing in this array should NOT be notified of /// the state change (note: if uContext is msoccontextMine, the only /// CompMgrs in rgpicmExclude that are checked for exclusion are those that /// are sub CompMgrs of this Component Manager, since all other CompMgrs /// are outside of this Component Manager's state context anyway.) /// /// Note: Calls to this method are symmetric with calls to /// FOnComponentExitState. /// That is, if n OnComponentEnterState calls are made, the component is /// considered to be in the state until n FOnComponentExitState calls are /// made. Before revoking its registration a component must make a /// sufficient number of FOnComponentExitState calls to offset any /// outstanding OnComponentEnterState calls it has made. /// /// Note: inplace objects should not call this method with /// uStateID == msocstateModal when entering modal state. Such objects /// should call IOleInPlaceFrame::EnableModeless instead. /// void UnsafeNativeMethods.IMsoComponentManager.OnComponentEnterState( int dwComponentID, int uStateID, int uContext, int cpicmExclude, int rgpicmExclude, // IMsoComponentManger** int dwReserved) { currentState |= uStateID; Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager: Component enter state. ID: " + dwComponentID.ToString(CultureInfo.InvariantCulture) + " state: " + uStateID.ToString(CultureInfo.InvariantCulture)); if (uContext == NativeMethods.MSOCM.msoccontextAll || uContext == NativeMethods.MSOCM.msoccontextMine) { Debug.Indent(); // We should notify all components we contain that the state has changed. // foreach (ComponentHashtableEntry entry in OleComponents.Values) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "Notifying " + entry.component.ToString()); entry.component.OnEnterState(uStateID, true); } Debug.Unindent(); } } ////// /// Notify component manager that component identified by dwComponentID /// (cookie returned from FRegisterComponent) is exiting the state /// identified by uStateID (a msocstateXXX value). (For convenience when /// dealing with sub CompMgrs, the host can call this method passing 0 for /// dwComponentID.) /// uContext, cpicmExclude, and rgpicmExclude are as they are in /// OnComponentEnterState. /// Component manager should notify all appropriate interested components /// (taking into account uContext, cpicmExclude, rgpicmExclude) via /// IMsoComponent::OnEnterState (see "Comments on State Contexts", above). /// Component Manager should also take appropriate action depending on /// the value of uStateID (see msocstate comments, above). /// Return TRUE if, at the end of this call, the state is still in effect /// at the root of this component manager's state context /// (because the host or some other component is still in the state), /// otherwise return FALSE (ie. return what FInState would return). /// Caller can normally ignore the return value. /// /// Note: n calls to this method are symmetric with n calls to /// OnComponentEnterState (see OnComponentEnterState comments, above). /// bool UnsafeNativeMethods.IMsoComponentManager.FOnComponentExitState( int dwComponentID, int uStateID, int uContext, int cpicmExclude, int rgpicmExclude // IMsoComponentManager** ) { currentState &= ~uStateID; Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager: Component exit state. ID: " + dwComponentID.ToString(CultureInfo.InvariantCulture) + " state: " + uStateID.ToString(CultureInfo.InvariantCulture)); if (uContext == NativeMethods.MSOCM.msoccontextAll || uContext == NativeMethods.MSOCM.msoccontextMine) { Debug.Indent(); // We should notify all components we contain that the state has changed. // foreach (ComponentHashtableEntry entry in OleComponents.Values) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "Notifying " + entry.component.ToString()); entry.component.OnEnterState(uStateID, false); } Debug.Unindent(); } return false; } ////// /// Return TRUE if the state identified by uStateID (a msocstateXXX value) /// is in effect at the root of this component manager's state context, /// FALSE otherwise (see "Comments on State Contexts", above). /// pvoid is reserved for future use and should be NULL. /// bool UnsafeNativeMethods.IMsoComponentManager.FInState(int uStateID, IntPtr pvoid) { return(currentState & uStateID) != 0; } ////// /// Called periodically by a component during IMsoComponent::FDoIdle. /// Return TRUE if component can continue its idle time processing, /// FALSE if not (in which case component returns from FDoIdle.) /// bool UnsafeNativeMethods.IMsoComponentManager.FContinueIdle() { // Essentially, if we have a message on queue, then don't continue // idle processing. // NativeMethods.MSG msg = new NativeMethods.MSG(); return !UnsafeNativeMethods.PeekMessage(ref msg, NativeMethods.NullHandleRef, 0, 0, NativeMethods.PM_NOREMOVE); } ////// /// Component identified by dwComponentID (cookie returned from /// FRegisterComponent) wishes to push a message loop for reason uReason. /// uReason is one the values from the msoloop enumeration (above). /// pvLoopData is data private to the component. /// The component manager should push its message loop, /// calling IMsoComponent::FContinueMessageLoop(uReason, pvLoopData) /// during each loop iteration (see IMsoComponent::FContinueMessageLoop /// comments). When IMsoComponent::FContinueMessageLoop returns FALSE, the /// component manager terminates the loop. /// Returns TRUE if component manager terminates loop because component /// told it to (by returning FALSE from IMsoComponent::FContinueMessageLoop), /// FALSE if it had to terminate the loop for some other reason. In the /// latter case, component should perform any necessary action (such as /// cleanup). /// bool UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop( int dwComponentID, int reason, int pvLoopData // PVOID ) { // Hold onto old state to allow restore before we exit... // int currentLoopState = currentState; bool continueLoop = true; if (!OleComponents.ContainsKey(dwComponentID)) { return false; } UnsafeNativeMethods.IMsoComponent prevActive = this.activeComponent; try { // Execute the message loop until the active component tells us to stop. // NativeMethods.MSG msg = new NativeMethods.MSG(); NativeMethods.MSG[] rgmsg = new NativeMethods.MSG[] {msg}; bool unicodeWindow = false; UnsafeNativeMethods.IMsoComponent requestingComponent; ComponentHashtableEntry entry = (ComponentHashtableEntry)OleComponents[dwComponentID]; if (entry == null) { return false; } requestingComponent = entry.component; this.activeComponent = requestingComponent; Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : Pushing message loop " + reason.ToString(CultureInfo.InvariantCulture)); Debug.Indent(); while (continueLoop) { // Determine the component to route the message to // UnsafeNativeMethods.IMsoComponent component; if (trackingComponent != null) { component = trackingComponent; } else if (activeComponent != null) { component = activeComponent; } else { component = requestingComponent; } bool peeked = UnsafeNativeMethods.PeekMessage(ref msg, NativeMethods.NullHandleRef, 0, 0, NativeMethods.PM_NOREMOVE); if (peeked) { rgmsg[0] = msg; continueLoop = component.FContinueMessageLoop(reason, pvLoopData, rgmsg); // If the component wants us to process the message, do it. // The component manager hosts windows from many places. We must be sensitive // to ansi / Unicode windows here. // if (continueLoop) { if (msg.hwnd != IntPtr.Zero && SafeNativeMethods.IsWindowUnicode(new HandleRef(null, msg.hwnd))) { unicodeWindow = true; UnsafeNativeMethods.GetMessageW(ref msg, NativeMethods.NullHandleRef, 0, 0); } else { unicodeWindow = false; UnsafeNativeMethods.GetMessageA(ref msg, NativeMethods.NullHandleRef, 0, 0); } if (msg.message == NativeMethods.WM_QUIT) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : Normal message loop termination"); Application.ThreadContext.FromCurrent().DisposeThreadWindows(); if (reason != NativeMethods.MSOCM.msoloopMain) { UnsafeNativeMethods.PostQuitMessage((int)msg.wParam); } continueLoop = false; break; } // Now translate and dispatch the message. // // Reading through the rather sparse documentation, // it seems we should only call FPreTranslateMessage // on the active component. But frankly, I'm afraid of what that might break. // See ASURT 29415 for more background. if (!component.FPreTranslateMessage(ref msg)) { UnsafeNativeMethods.TranslateMessage(ref msg); if (unicodeWindow) { UnsafeNativeMethods.DispatchMessageW(ref msg); } else { UnsafeNativeMethods.DispatchMessageA(ref msg); } } } } else { // If this is a DoEvents loop, then get out. There's nothing left // for us to do. // if (reason == NativeMethods.MSOCM.msoloopDoEvents || reason == NativeMethods.MSOCM.msoloopDoEventsModal) { break; } // Nothing is on the message queue. Perform idle processing // and then do a WaitMessage. // bool continueIdle = false; if (OleComponents != null) { IEnumerator enumerator = OleComponents.Values.GetEnumerator(); while (enumerator.MoveNext()) { ComponentHashtableEntry idleEntry = (ComponentHashtableEntry)enumerator.Current; continueIdle |= idleEntry.component.FDoIdle(-1); } } // give the component one more chance to terminate the // message loop. // continueLoop = component.FContinueMessageLoop(reason, pvLoopData, null); if (continueLoop) { if (continueIdle) { // If someone has asked for idle time, give it to them. However, // don't cycle immediately; wait up to 100ms. Why? Because we don't // want someone to attach to idle, forget to detach, and then ---- // the CPU. For Windows Forms this generally isn't an issue because // our component always returns false from its idle request UnsafeNativeMethods.MsgWaitForMultipleObjectsEx(0, IntPtr.Zero, 100, NativeMethods.QS_ALLINPUT, NativeMethods.MWMO_INPUTAVAILABLE); } else { // We should call GetMessage here, but we cannot because // the component manager requires that we notify the // active component before we pull the message off the // queue. This is a bit of a problem, because WaitMessage // waits for a NEW message to appear on the queue. If a // message appeared between processing and now WaitMessage // would wait for the next message. We minimize this here // by calling PeekMessage. // if (!UnsafeNativeMethods.PeekMessage(ref msg, NativeMethods.NullHandleRef, 0, 0, NativeMethods.PM_NOREMOVE)) { UnsafeNativeMethods.WaitMessage(); } } } } } Debug.Unindent(); Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : message loop " + reason.ToString(CultureInfo.InvariantCulture) + " complete."); } finally { currentState = currentLoopState; this.activeComponent = prevActive; } return !continueLoop; } ////// /// Cause the component manager to create a "sub" component manager, which /// will be one of its children in the hierarchical tree of component /// managers used to maintiain state contexts (see "Comments on State /// Contexts", above). /// piunkOuter is the controlling unknown (can be NULL), riid is the /// desired IID, and *ppvObj returns the created sub component manager. /// piunkServProv (can be NULL) is a ptr to an object supporting /// IServiceProvider interface to which the created sub component manager /// will delegate its IMsoComponentManager::QueryService calls. /// (see objext.h or docobj.h for definition of IServiceProvider). /// Returns TRUE if successful. /// bool UnsafeNativeMethods.IMsoComponentManager.FCreateSubComponentManager( object punkOuter, object punkServProv, ref Guid riid, out IntPtr ppvObj) { // We do not support sub component managers. // ppvObj = IntPtr.Zero; return false; } ////// /// Return in *ppicm an AddRef'ed ptr to this component manager's parent /// in the hierarchical tree of component managers used to maintain state /// contexts (see "Comments on State Contexts", above). /// Returns TRUE if the parent is returned, FALSE if no parent exists or /// some error occurred. /// bool UnsafeNativeMethods.IMsoComponentManager.FGetParentComponentManager(out UnsafeNativeMethods.IMsoComponentManager ppicm) { ppicm = null; return false; } ////// /// Return in *ppic an AddRef'ed ptr to the current active or tracking /// component (as indicated by dwgac (a msogacXXX value)), and /// its registration information in *pcrinfo. ppic and/or pcrinfo can be /// NULL if caller is not interested these values. If pcrinfo is not NULL, /// caller should set pcrinfo->cbSize before calling this method. /// Returns TRUE if the component indicated by dwgac exists, FALSE if no /// such component exists or some error occurred. /// dwReserved is reserved for future use and should be zero. /// bool UnsafeNativeMethods.IMsoComponentManager.FGetActiveComponent( int dwgac, UnsafeNativeMethods.IMsoComponent[] ppic, NativeMethods.MSOCRINFOSTRUCT info, int dwReserved) { UnsafeNativeMethods.IMsoComponent component = null; if (dwgac == NativeMethods.MSOCM.msogacActive) { component = activeComponent; } else if (dwgac == NativeMethods.MSOCM.msogacTracking) { component = trackingComponent; } else if (dwgac == NativeMethods.MSOCM.msogacTrackingOrActive) { if (trackingComponent != null) { component = trackingComponent; } else { component = activeComponent; } } else { Debug.Fail("Unknown dwgac in FGetActiveComponent"); } if (ppic != null) { ppic[0] = component; } if (info != null && component != null) { foreach(ComponentHashtableEntry entry in OleComponents.Values) { if (entry.component == component) { info = entry.componentInfo; break; } } } return component != null; } } ////// /// This class is the embodiment of TLS for windows forms. We do not expose this to end users because /// TLS is really just an unfortunate artifact of using Win 32. We want the world to be free /// threaded. /// ///internal sealed class ThreadContext : MarshalByRefObject, UnsafeNativeMethods.IMsoComponent { private const int STATE_OLEINITIALIZED = 0x00000001; private const int STATE_EXTERNALOLEINIT = 0x00000002; private const int STATE_INTHREADEXCEPTION = 0x00000004; private const int STATE_POSTEDQUIT = 0x00000008; private const int STATE_FILTERSNAPSHOTVALID = 0x00000010; private const int STATE_TRACKINGCOMPONENT = 0x00000020; private const int INVALID_ID = unchecked((int)0xFFFFFFFF); private static Hashtable contextHash = new Hashtable(); // When this gets to zero, we'll invoke a full garbage // collect and check for root/window leaks. // private static object tcInternalSyncObject = new object(); private static int totalMessageLoopCount; private static int baseLoopReason; [ ThreadStatic ] private static ThreadContext currentThreadContext; internal ThreadExceptionEventHandler threadExceptionHandler; internal EventHandler idleHandler; internal EventHandler enterModalHandler; internal EventHandler leaveModalHandler; private ApplicationContext applicationContext; private ParkingWindow parkingWindow; private Control marshalingControl; private CultureInfo culture; private ArrayList messageFilters; private IMessageFilter[] messageFilterSnapshot; private IntPtr handle; private int id; private int messageLoopCount; private int threadState; private int modalCount; // used for correct restoration of focus after modality private WeakReference activatingControlRef; // IMsoComponentManager stuff // private UnsafeNativeMethods.IMsoComponentManager componentManager; private bool externalComponentManager; private bool fetchingComponentManager; // IMsoComponent stuff private int componentID = INVALID_ID; private Form currentForm; private ThreadWindows threadWindows; private NativeMethods.MSG tempMsg = new NativeMethods.MSG(); private int disposeCount; // To make sure that we don't allow // reentrancy in Dispose() // Debug helper variable #if DEBUG private int debugModalCounter; #endif // Refer VSWhidbey 258748 // Refer VS Whidbey 337882 // We need to set this flag if we have started the ModalMessageLoop so that we dont create the ThreadWindows // when the ComponentManager calls on us (as IMSOComponent) during the OnEnterState. private bool ourModalLoop; // A private field on Application that stores the callback delegate private MessageLoopCallback messageLoopCallback = null; /// /// /// Creates a new thread context object. /// public ThreadContext() { IntPtr address = IntPtr.Zero; UnsafeNativeMethods.DuplicateHandle(new HandleRef(null, SafeNativeMethods.GetCurrentProcess()), new HandleRef(null, SafeNativeMethods.GetCurrentThread()), new HandleRef(null, SafeNativeMethods.GetCurrentProcess()), ref address, 0, false, NativeMethods.DUPLICATE_SAME_ACCESS); handle = address; id = SafeNativeMethods.GetCurrentThreadId(); messageLoopCount = 0; currentThreadContext = this; contextHash[id] = this; } public ApplicationContext ApplicationContext { get { return applicationContext; } } ////// /// Retrieves the component manager for this process. If there is no component manager /// currently installed, we install our own. /// internal UnsafeNativeMethods.IMsoComponentManager ComponentManager { get { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "Application.ComponentManager.Get:"); if (componentManager == null) { // The CLR is a good COM citizen and will pump messages when things are waiting. // This is nice; it keeps the world responsive. But, it is also very hard for // us because most of the code below causes waits, and the likelihood that // a message will come in and need a component manager is very high. Recursing // here is very very bad, and will almost certainly lead to application failure // later on as we come out of the recursion. So, we guard it here and return // null. EVERYONE who accesses the component manager must handle a NULL return! // if (fetchingComponentManager) { return null; } fetchingComponentManager = true; try { UnsafeNativeMethods.IMsoComponentManager msocm = null; Application.OleRequired(); // Attempt to obtain the Host Application MSOComponentManager // IntPtr msgFilterPtr = (IntPtr)0; if (NativeMethods.Succeeded(UnsafeNativeMethods.CoRegisterMessageFilter(NativeMethods.NullHandleRef, ref msgFilterPtr)) && msgFilterPtr != (IntPtr)0) { IntPtr dummy = (IntPtr)0; UnsafeNativeMethods.CoRegisterMessageFilter(new HandleRef(null, msgFilterPtr), ref dummy); object msgFilterObj = Marshal.GetObjectForIUnknown(msgFilterPtr); Marshal.Release(msgFilterPtr); UnsafeNativeMethods.IOleServiceProvider sp = msgFilterObj as UnsafeNativeMethods.IOleServiceProvider; if (sp != null) { try { IntPtr retval = IntPtr.Zero; // PERF ALERT ([....]): Using typeof() of COM object spins up COM at JIT time. // Guid compModGuid = typeof(UnsafeNativeMethods.SMsoComponentManager).GUID; // Guid compModGuid = new Guid("000C060B-0000-0000-C000-000000000046"); Guid iid = new Guid("{000C0601-0000-0000-C000-000000000046}"); int hr = sp.QueryService( ref compModGuid, ref iid, out retval); if (NativeMethods.Succeeded(hr) && retval != IntPtr.Zero) { // Now query for hte message filter. IntPtr pmsocm; try { Guid IID_IMsoComponentManager = typeof(UnsafeNativeMethods.IMsoComponentManager).GUID; hr = Marshal.QueryInterface(retval, ref IID_IMsoComponentManager, out pmsocm); } finally { Marshal.Release(retval); } if (NativeMethods.Succeeded(hr) && pmsocm != IntPtr.Zero) { // Ok, we have a native component manager. Hand this over to // our broker object to get a proxy we can use try { msocm = ComponentManagerBroker.GetComponentManager(pmsocm); } finally { Marshal.Release(pmsocm); } } if (msocm != null) { // If the resulting service is the same pUnk as the // message filter (a common implementation technique), // then we want to null msgFilterObj at this point so // we don't call RelaseComObject on it below. That would // also release the RCW for the component manager pointer. if (msgFilterPtr == retval) { msgFilterObj = null; } externalComponentManager = true; Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "Using MSO Component manager"); // Now attach app domain unload events so we can // detect when we need to revoke our component // AppDomain.CurrentDomain.DomainUnload += new EventHandler(OnDomainUnload); AppDomain.CurrentDomain.ProcessExit += new EventHandler(OnDomainUnload); } } } catch { } } if (msgFilterObj != null && Marshal.IsComObject(msgFilterObj)) { Marshal.ReleaseComObject(msgFilterObj); } } // Otherwise, we implement component manager ourselves // if (msocm == null) { msocm = new ComponentManager(); externalComponentManager = false; // We must also store this back into the message filter for others // to use. // // Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "Using our own component manager"); } if (msocm != null && componentID == INVALID_ID) { // Finally, if we got a compnent manager, register ourselves with it. // Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "Registering MSO component with the component manager"); NativeMethods.MSOCRINFOSTRUCT info = new NativeMethods.MSOCRINFOSTRUCT(); info.cbSize = Marshal.SizeOf(typeof(NativeMethods.MSOCRINFOSTRUCT)); info.uIdleTimeInterval = 0; info.grfcrf = NativeMethods.MSOCM.msocrfPreTranslateAll | NativeMethods.MSOCM.msocrfNeedIdleTime; info.grfcadvf = NativeMethods.MSOCM.msocadvfModal; bool result = msocm.FRegisterComponent(this, info, out componentID); Debug.Assert(componentID != INVALID_ID, "Our ID sentinel was returned as a valid ID"); if (result && !(msocm is ComponentManager)) { messageLoopCount++; } Debug.Assert(result, "Failed to register WindowsForms with the ComponentManager -- DoEvents and modal dialogs will be broken. size: " + info.cbSize); Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager.FRegisterComponent returned " + result.ToString()); Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager.FRegisterComponent assigned a componentID == [0x" + Convert.ToString(componentID, 16) + "]"); componentManager = msocm; } } finally { fetchingComponentManager = false; } } return componentManager; } } internal bool CustomThreadExceptionHandlerAttached { get { return threadExceptionHandler != null; } } ////// /// Retrieves the actual parking form. This will demand create the parking window /// if it needs to. /// ///internal ParkingWindow ParkingWindow { get { // Locking 'this' here is ok since this is an internal class. See VSW#464499. lock(this) { if (parkingWindow == null) { #if DEBUG // if we use Debug.WriteLine instead of "if", we need extra security permissions // to get the stack trace! if (CoreSwitches.PerfTrack.Enabled) { Debug.WriteLine("Creating parking form!"); Debug.WriteLine(CoreSwitches.PerfTrack.Enabled, Environment.StackTrace); } #endif // SECREVIEW : We need to create the parking window. Since this is a top // : level hidden form, we must assert this. However, the parking // : window is complete internal to the assembly, so no one can // : ever get at it. // IntSecurity.ManipulateWndProcAndHandles.Assert(); try { parkingWindow = new ParkingWindow(); } finally { CodeAccessPermission.RevertAssert(); } } return parkingWindow; } } } internal Control ActivatingControl { get { if ((activatingControlRef != null) && (activatingControlRef.IsAlive)) { return activatingControlRef.Target as Control; } return null; } set { if (value != null) { activatingControlRef = new WeakReference(value); } else { activatingControlRef = null; } } } /// /// /// Retrieves the actual parking form. This will demand create the MarshalingControl window /// if it needs to. /// ///internal Control MarshalingControl { get { lock (this) { if (marshalingControl == null) { #if DEBUG // if we use Debug.WriteLine instead of "if", we need extra security permissions // to get the stack trace! if (CoreSwitches.PerfTrack.Enabled) { Debug.WriteLine("Creating marshalling control!"); Debug.WriteLine(CoreSwitches.PerfTrack.Enabled, Environment.StackTrace); } #endif marshalingControl = new System.Windows.Forms.Application.MarshalingControl(); } return marshalingControl; } } } /// /// /// Allows you to setup a message filter for the application's message pump. This /// installs the filter on the current thread. /// ///internal void AddMessageFilter(IMessageFilter f) { if (messageFilters == null) { messageFilters = new ArrayList(); } if (f != null) { SetState(STATE_FILTERSNAPSHOTVALID, false); if (messageFilters.Count > 0 && f is IMessageModifyAndFilter) { // insert the IMessageModifyAndFilter filters first messageFilters.Insert(0, f); } else { messageFilters.Add(f); } } } // Called immediately before we begin pumping messages for a modal message loop. internal void BeginModalMessageLoop(ApplicationContext context) { #if DEBUG debugModalCounter++; #endif // Set the ourModalLoop flag so that the "IMSOComponent.OnEnterState" is a NOOP since we started the ModalMessageLoop. bool wasOurLoop = ourModalLoop; ourModalLoop = true; try { UnsafeNativeMethods.IMsoComponentManager cm = ComponentManager; if (cm != null) { cm.OnComponentEnterState(componentID, NativeMethods.MSOCM.msocstateModal, NativeMethods.MSOCM.msoccontextAll, 0, 0, 0); } } finally { ourModalLoop = wasOurLoop; } // This will initialize the ThreadWindows with proper flags. DisableWindowsForModalLoop(false, context); // onlyWinForms = false modalCount++; if (enterModalHandler != null && modalCount == 1) { enterModalHandler(Thread.CurrentThread, EventArgs.Empty); } } // Disables windows in preparation of going modal. If parameter is true, we disable all // windows, if false, only windows forms windows (i.e., windows controlled by this MsoComponent). // See also IMsoComponent.OnEnterState. internal void DisableWindowsForModalLoop(bool onlyWinForms, ApplicationContext context) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : Entering modal state"); ThreadWindows old = threadWindows; threadWindows = new ThreadWindows(onlyWinForms); threadWindows.Enable(false); threadWindows.previousThreadWindows = old; ModalApplicationContext modalContext = context as ModalApplicationContext; if (modalContext != null) { modalContext.DisableThreadWindows(true, onlyWinForms); } } /// /// /// Disposes this thread context object. Note that this will marshal to the owning thread. /// ///internal void Dispose(bool postQuit) { // need to avoid multiple threads coming in here or we'll leak the thread // handle. // lock (this) { try { if (disposeCount++ == 0) { // make sure that we are not reentrant // Unravel our message loop. this will marshal us over to // the right thread, making the dispose() method async. if (messageLoopCount > 0 && postQuit) { PostQuit(); } else { bool ourThread = SafeNativeMethods.GetCurrentThreadId() == id; try { // We can only clean up if we're being called on our // own thread. // if (ourThread) { // If we had a component manager, detach from it. // if (componentManager != null) { RevokeComponent(); // } // DisposeAssociatedComponents(); DisposeThreadWindows(); try { Application.RaiseThreadExit(); } finally { if (GetState(STATE_OLEINITIALIZED) && !GetState(STATE_EXTERNALOLEINIT)) { SetState(STATE_OLEINITIALIZED, false); UnsafeNativeMethods.OleUninitialize(); } } } } finally { // We can always clean up this handle, though // if (handle != IntPtr.Zero) { UnsafeNativeMethods.CloseHandle(new HandleRef(this, handle)); handle = IntPtr.Zero; } try { if (totalMessageLoopCount == 0) { Application.RaiseExit(); } } finally { contextHash.Remove((object)id); if (currentThreadContext == this) { currentThreadContext = null; } } } } GC.SuppressFinalize(this); } } finally { disposeCount--; } } } /// /// /// Disposes of this thread's parking form. /// ///private void DisposeParkingWindow() { if (parkingWindow != null && parkingWindow.IsHandleCreated) { // We take two paths here. If we are on the same thread as // the parking window, we can destroy its handle. If not, // we just null it and let it GC. When it finalizes it // will disconnect its handle and post a WM_CLOSE. // // It is important that we just call DestroyHandle here // and do not call Dispose. Otherwise we would destroy // controls that are living on the parking window. // int pid; int hwndThread = SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(parkingWindow, parkingWindow.Handle), out pid); int currentThread = SafeNativeMethods.GetCurrentThreadId(); if (hwndThread == currentThread) { parkingWindow.Destroy(); } else { parkingWindow = null; } } } /// /// /// Gets rid of all windows in this thread context. Nulls out /// window objects that we hang on to. /// internal void DisposeThreadWindows() { // We dispose the main window first, so it can perform any // cleanup that it may need to do. // try { if (applicationContext != null) { applicationContext.Dispose(); applicationContext = null; } // Then, we rudely destroy all of the windows on the thread // ThreadWindows tw = new ThreadWindows(true); tw.Dispose(); // And dispose the parking form, if it isn't already // DisposeParkingWindow(); } catch { } } // Enables windows in preparation of stopping modal. If parameter is true, we enable all windows, // if false, only windows forms windows (i.e., windows controlled by this MsoComponent). // See also IMsoComponent.OnEnterState. internal void EnableWindowsForModalLoop(bool onlyWinForms, ApplicationContext context) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : Leaving modal state"); if (threadWindows != null) { threadWindows.Enable(true); Debug.Assert(threadWindows != null, "OnEnterState recursed, but it's not supposed to be reentrant"); threadWindows = threadWindows.previousThreadWindows; } ModalApplicationContext modalContext = context as ModalApplicationContext; if (modalContext != null) { modalContext.DisableThreadWindows(false, onlyWinForms); } } // Called immediately after we end pumping messages for a modal message loop. internal void EndModalMessageLoop(ApplicationContext context) { #if DEBUG debugModalCounter--; Debug.Assert(debugModalCounter >= 0, "Mis-matched calls to Application.BeginModalMessageLoop() and Application.EndModalMessageLoop()"); #endif // This will re-enable the windows... EnableWindowsForModalLoop(false, context); // onlyWinForms = false bool wasOurLoop = ourModalLoop; ourModalLoop = true; try { // If We started the ModalMessageLoop .. this will call us back on the IMSOComponent.OnStateEnter and not do anything ... UnsafeNativeMethods.IMsoComponentManager cm = ComponentManager; if (cm != null) { cm.FOnComponentExitState(componentID, NativeMethods.MSOCM.msocstateModal, NativeMethods.MSOCM.msoccontextAll, 0, 0); } } finally { // Reset the flag since we are exiting out of a ModalMesaageLoop.. ourModalLoop = wasOurLoop; } modalCount--; if (leaveModalHandler != null && modalCount == 0) { leaveModalHandler(Thread.CurrentThread, EventArgs.Empty); } } ////// /// Exits the program by disposing of all thread contexts and message loops. /// ///internal static void ExitApplication() { ExitCommon(true /*disposing*/); } private static void ExitCommon(bool disposing) { lock(tcInternalSyncObject) { if (contextHash != null) { ThreadContext[] ctxs = new ThreadContext[contextHash.Values.Count]; contextHash.Values.CopyTo(ctxs, 0); for (int i = 0; i < ctxs.Length; ++i) { if (ctxs[i].ApplicationContext != null) { ctxs[i].ApplicationContext.ExitThread(); } else { ctxs[i].Dispose(disposing); } } } } } /// /// /// Exits the program by disposing of all thread contexts and message loops. /// ///internal static void ExitDomain() { ExitCommon(false /*disposing*/); } /// /// /// Our finalization. Minimal stuff... this shouldn't be called... We should always be disposed. /// ///~ThreadContext() { // VSWhidbey 169487 We used to call OleUninitialize() here if we were // still STATE_OLEINITIALIZED, but that's never the correct thing to do. // At this point we're on the wrong thread and we should never have been // called here in the first place. // We can always clean up this handle, though // if (handle != IntPtr.Zero) { UnsafeNativeMethods.CloseHandle(new HandleRef(this, handle)); handle = IntPtr.Zero; } } // When a Form receives a WM_ACTIVATE message, it calls this method so we can do the // appropriate MsoComponentManager activation magic internal void FormActivated(bool activate) { if (activate) { UnsafeNativeMethods.IMsoComponentManager cm = ComponentManager; if (cm != null && !(cm is ComponentManager)) { cm.FOnComponentActivate(componentID); } } } // Sets this component as the tracking component - trumping any active component // for message filtering. internal void TrackInput(bool track) { // VSWhidbey 409264 // protect against double setting, as this causes asserts in the VS component manager. if (track != GetState(STATE_TRACKINGCOMPONENT)) { UnsafeNativeMethods.IMsoComponentManager cm = ComponentManager; if (cm != null && !(cm is ComponentManager)) { cm.FSetTrackingComponent(componentID, track); SetState(STATE_TRACKINGCOMPONENT, track); } } } /// /// /// Retrieves a ThreadContext object for the current thread /// ///internal static ThreadContext FromCurrent() { ThreadContext context = currentThreadContext; if (context == null) { context = new ThreadContext(); } return context; } /// /// /// Retrieves a ThreadContext object for the given thread ID /// ///internal static ThreadContext FromId(int id) { ThreadContext context = (ThreadContext)contextHash[(object)id]; if (context == null && id == SafeNativeMethods.GetCurrentThreadId()) { context = new ThreadContext(); } return context; } /// /// /// Determines if it is OK to allow an application to quit and shutdown /// the runtime. We only allow this if we own the base message pump. /// internal bool GetAllowQuit() { return totalMessageLoopCount > 0 && baseLoopReason == NativeMethods.MSOCM.msoloopMain; } ////// /// Retrieves the handle to this thread. /// ///internal IntPtr GetHandle() { return handle; } /// /// /// Retrieves the ID of this thread. /// ///internal int GetId() { return id; } /// /// /// Retrieves the culture for this thread. /// ///internal CultureInfo GetCulture() { if (culture == null || culture.LCID != SafeNativeMethods.GetThreadLocale()) culture = new CultureInfo(SafeNativeMethods.GetThreadLocale()); return culture; } /// /// /// Determines if a message loop exists on this thread. /// internal bool GetMessageLoop() { return GetMessageLoop(false); } ////// /// Determines if a message loop exists on this thread. /// internal bool GetMessageLoop(bool mustBeActive) { // If we are already running a loop, we're fine. // If we are running in external manager we may need to make sure first the loop is active // if (messageLoopCount > (mustBeActive && externalComponentManager ? 1 : 0)) { return true; } // Also, access the ComponentManager property to demand create it, and we're also // fine if it is an external manager, because it has already pushed a loop. // if (ComponentManager != null && externalComponentManager) { if (mustBeActive == false) { return true; } UnsafeNativeMethods.IMsoComponent[] activeComponents = new UnsafeNativeMethods.IMsoComponent[1]; if (ComponentManager.FGetActiveComponent(NativeMethods.MSOCM.msogacActive, activeComponents, null, 0) && activeComponents[0] == this) { return true; } } // Finally, check if a message loop has been registered MessageLoopCallback callback = messageLoopCallback; if (callback != null) { return callback(); } // Otherwise, we do not have a loop running. // return false; } private bool GetState(int bit) { return(threadState & bit) != 0; } ////// Keep the object alive forever. /// public override object InitializeLifetimeService() { return null; } ////// A method of determining whether we are handling messages that does not demand register /// the componentmanager /// ///internal bool IsValidComponentId() { return (componentID != INVALID_ID); } internal System.Threading.ApartmentState OleRequired() { Thread current = Thread.CurrentThread; if (!GetState(STATE_OLEINITIALIZED)) { int ret = UnsafeNativeMethods.OleInitialize(); #if false // PERFTRACK : [....], 7/26/1999 - To avoid constructing the string in // : non-failure cases (vast majority), we will do the debug.fail // : inside an if statement. // if (!(ret == NativeMethods.S_OK || ret == NativeMethods.S_FALSE || ret == NativeMethods.RPC_E_CHANGED_MODE)) { Debug.Assert(ret == NativeMethods.S_OK || ret == NativeMethods.S_FALSE || ret == NativeMethods.RPC_E_CHANGED_MODE, "OLE Failed to Initialize!. RetCode: 0x" + Convert.ToString(ret, 16) + " LastError: " + Marshal.GetLastWin32Error().ToString()); } #endif SetState(STATE_OLEINITIALIZED, true); if (ret == NativeMethods.RPC_E_CHANGED_MODE) { // This could happen if the thread was already initialized for MTA // and then we call OleInitialize which tries to initialized it for STA // This currently happens while profiling... SetState(STATE_EXTERNALOLEINIT, true); } } if ( GetState( STATE_EXTERNALOLEINIT )) { return System.Threading.ApartmentState.MTA; } else { return System.Threading.ApartmentState.STA; } } private void OnAppThreadExit(object sender, EventArgs e) { Dispose(true); } /// /// Revokes our component if needed. /// [PrePrepareMethod] private void OnDomainUnload(object sender, EventArgs e) { RevokeComponent(); ExitDomain(); } ////// /// Called when an untrapped exception occurs in a thread. This allows the /// programmer to trap these, and, if left untrapped, throws a standard error /// dialog. /// ///internal void OnThreadException(Exception t) { if (GetState(STATE_INTHREADEXCEPTION)) return; SetState(STATE_INTHREADEXCEPTION, true); try { if (threadExceptionHandler != null) { threadExceptionHandler(Thread.CurrentThread, new ThreadExceptionEventArgs(t)); } else { if (SystemInformation.UserInteractive) { ThreadExceptionDialog td = new ThreadExceptionDialog(t); DialogResult result = DialogResult.OK; // SECREVIEW : This Assert is ok, this dialog shows up when the application is about to die. // ShowDialog will generate a call to ContainerControl.SetActiveControl which demands // ModifyFocus permission, need to assert it here. // IntSecurity.ModifyFocus.Assert(); try { result = td.ShowDialog(); } finally { CodeAccessPermission.RevertAssert(); td.Dispose(); } switch (result) { case DialogResult.Abort: // SECREVIEW : The user clicked "Quit" in response to a exception dialog. // : We only show the quit option when we own the message pump, // : so this won't ever tear down IE or any other ActiveX host. // : // : This has a potential problem where a component could // : cause a failure, then try a "trick" the user into hitting // : quit. However, no component or application outside of // : the windows forms assembly can modify the dialog, so this is // : a really minor concern. // Application.ExitInternal(); // SECREVIEW : We can't revert this assert... after Exit(0) is called, no // : more code is executed... // new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); Environment.Exit(0); break; case DialogResult.Yes: WarningException w = t as WarningException; if (w != null) { Help.ShowHelp(null, w.HelpUrl, w.HelpTopic); } break; } } else { // Ignore unhandled thread exceptions. The user can // override if they really care. // } } } finally { SetState(STATE_INTHREADEXCEPTION, false); } } internal void PostQuit() { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : Attempting to terminate message loop"); // Per http://support.microsoft.com/support/kb/articles/Q183/1/16.ASP // // WM_QUIT may be consumed by another message pump under very specific circumstances. // When that occurs, we rely on the STATE_POSTEDQUIT to be caught in the next // idle, at which point we can tear down. // // We can't follow the KB article exactly, becasue we don't have an HWND to PostMessage // to. // UnsafeNativeMethods.PostThreadMessage(id, NativeMethods.WM_QUIT, IntPtr.Zero, IntPtr.Zero); SetState(STATE_POSTEDQUIT, true); } // Allows the hosting environment to register a callback internal void RegisterMessageLoop(MessageLoopCallback callback) { messageLoopCallback = callback; } /// /// /// Removes a message filter previously installed with addMessageFilter. /// ///internal void RemoveMessageFilter(IMessageFilter f) { if (messageFilters != null) { SetState(STATE_FILTERSNAPSHOTVALID, false); messageFilters.Remove(f); } } /// /// /// Starts a message loop for the given reason. /// ///internal void RunMessageLoop(int reason, ApplicationContext context) { // Ensure that we attempt to apply theming before doing anything // that might create a window. IntPtr userCookie = IntPtr.Zero; if (useVisualStyles) { userCookie = UnsafeNativeMethods.ThemingScope.Activate(); } try { RunMessageLoopInner(reason, context); } finally { UnsafeNativeMethods.ThemingScope.Deactivate(userCookie); } } private void RunMessageLoopInner(int reason, ApplicationContext context) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ThreadContext.PushMessageLoop {"); Debug.Indent(); if (reason == NativeMethods.MSOCM.msoloopModalForm && !SystemInformation.UserInteractive) { throw new InvalidOperationException(SR.GetString(SR.CantShowModalOnNonInteractive)); } // if we've entered because of a Main message loop being pushed // (different than a modal message loop or DoEVents loop) // then clear the QUIT flag to allow normal processing. // this flag gets set during loop teardown for another form. if (reason == NativeMethods.MSOCM.msoloopMain) { SetState(STATE_POSTEDQUIT, false); } if (totalMessageLoopCount++ == 0) { baseLoopReason = reason; } messageLoopCount++; if (reason == NativeMethods.MSOCM.msoloopMain) { // If someone has tried to push another main message loop on this thread, ignore // it. if (messageLoopCount != 1) { throw new InvalidOperationException(SR.GetString(SR.CantNestMessageLoops)); } applicationContext = context; applicationContext.ThreadExit += new EventHandler(OnAppThreadExit); if (applicationContext.MainForm != null) { applicationContext.MainForm.Visible = true; } } Form oldForm = currentForm; if (context != null) { currentForm = context.MainForm; } bool fullModal = false; bool localModal = false; HandleRef hwndOwner = new HandleRef(null, IntPtr.Zero); if (reason == NativeMethods.MSOCM.msoloopDoEventsModal) { localModal = true; } if (reason == NativeMethods.MSOCM.msoloopModalForm || reason == NativeMethods.MSOCM.msoloopModalAlert) { fullModal = true; // We're about to disable all windows in the thread so our modal dialog can be the top dog. Because this can interact // with external MSO things, and also because the modal dialog could have already had its handle created, // Check to see if the handle exists and if the window is currently enabled. We remember this so we can set the // window back to enabled after disabling everyone else. This is just a precaution against someone doing the // wrong thing and disabling our dialog. // bool modalEnabled = currentForm != null && currentForm.Enabled; Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "[0x" + Convert.ToString(componentID, 16) + "] Notifying component manager that we are entering a modal loop"); BeginModalMessageLoop(context); // If the owner window of the dialog is still enabled, disable it now. // This can happen if the owner window is from a different thread or // process. hwndOwner = new HandleRef(null, UnsafeNativeMethods.GetWindowLong(new HandleRef(currentForm, currentForm.Handle), NativeMethods.GWL_HWNDPARENT)); if (hwndOwner.Handle != IntPtr.Zero) { if (SafeNativeMethods.IsWindowEnabled(hwndOwner)) { SafeNativeMethods.EnableWindow(hwndOwner, false); } else { // reset hwndOwner so we are not tempted to // fiddle with it hwndOwner = new HandleRef(null, IntPtr.Zero); } } // The second half of the the modalEnabled flag above. Here, if we were previously // enabled, make sure that's still the case. // if (currentForm != null && currentForm.IsHandleCreated && SafeNativeMethods.IsWindowEnabled(new HandleRef(currentForm, currentForm.Handle)) != modalEnabled) { SafeNativeMethods.EnableWindow(new HandleRef(currentForm, currentForm.Handle), modalEnabled); } } try { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "[0x" + Convert.ToString(componentID, 16) + "] Calling ComponentManager.FPushMessageLoop..."); bool result; // Register marshaller for background tasks. At this point, // need to be able to successfully get the handle to the // parking window. Only do it when we're entering the first // message loop for this thread. if (messageLoopCount == 1) { WindowsFormsSynchronizationContext.InstallIfNeeded(); } //need to do this in a try/finally. Also good to do after we installed the synch context. if (fullModal && currentForm != null) { currentForm.Visible = true; } if ((!fullModal && !localModal) || ComponentManager is ComponentManager) { result = ComponentManager.FPushMessageLoop(componentID, reason, 0); } else if (reason == NativeMethods.MSOCM.msoloopDoEvents || reason == NativeMethods.MSOCM.msoloopDoEventsModal) { result = LocalModalMessageLoop(null); } else { result = LocalModalMessageLoop(currentForm); } Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "[0x" + Convert.ToString(componentID, 16) + "] ComponentManager.FPushMessageLoop returned " + result.ToString()); } finally { if (fullModal) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "[0x" + Convert.ToString(componentID, 16) + "] Notifying component manager that we are exiting a modal loop"); EndModalMessageLoop(context); // Again, if the hwndOwner was valid and disabled above, re-enable it. if (hwndOwner.Handle != IntPtr.Zero) { SafeNativeMethods.EnableWindow(hwndOwner, true); } } currentForm = oldForm; totalMessageLoopCount--; messageLoopCount--; if (messageLoopCount == 0) { // If last message loop shutting down, install the // previous op [....] context in place before we started the first // message loop. WindowsFormsSynchronizationContext.Uninstall(false); } if (reason == NativeMethods.MSOCM.msoloopMain) { Dispose(true); } else if (messageLoopCount == 0 && componentManager != null) { // If we had a component manager, detach from it. // RevokeComponent(); } } Debug.Unindent(); Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "}"); } private bool LocalModalMessageLoop(Form form) { try { // Execute the message loop until the active component tells us to stop. // NativeMethods.MSG msg = new NativeMethods.MSG(); bool unicodeWindow = false; bool continueLoop = true; while (continueLoop) { bool peeked = UnsafeNativeMethods.PeekMessage(ref msg, NativeMethods.NullHandleRef, 0, 0, NativeMethods.PM_NOREMOVE); if (peeked) { // If the component wants us to process the message, do it. // The component manager hosts windows from many places. We must be sensitive // to ansi / Unicode windows here. // if (msg.hwnd != IntPtr.Zero && SafeNativeMethods.IsWindowUnicode(new HandleRef(null, msg.hwnd))) { unicodeWindow = true; if (!UnsafeNativeMethods.GetMessageW(ref msg, NativeMethods.NullHandleRef, 0, 0)) { continue; } } else { unicodeWindow = false; if (!UnsafeNativeMethods.GetMessageA(ref msg, NativeMethods.NullHandleRef, 0, 0)) { continue; } } if (!PreTranslateMessage(ref msg)) { UnsafeNativeMethods.TranslateMessage(ref msg); if (unicodeWindow) { UnsafeNativeMethods.DispatchMessageW(ref msg); } else { UnsafeNativeMethods.DispatchMessageA(ref msg); } } if (form != null) { continueLoop = !form.CheckCloseDialog(false); } } else if (form == null) { break; } else if (!UnsafeNativeMethods.PeekMessage(ref msg, NativeMethods.NullHandleRef, 0, 0, NativeMethods.PM_NOREMOVE)) { UnsafeNativeMethods.WaitMessage(); } } return continueLoop; } catch { return false; } } internal bool ProcessFilters(ref NativeMethods.MSG msg, out bool modified) { bool filtered = false; modified = false; // Account for the case where someone removes a message filter // as a result of PreFilterMessage. the message filter will be // removed from _the next_ message. if (messageFilters != null && !GetState(STATE_FILTERSNAPSHOTVALID)) { if (messageFilters.Count > 0) { messageFilterSnapshot = new IMessageFilter[messageFilters.Count]; messageFilters.CopyTo(messageFilterSnapshot); } else { messageFilterSnapshot = null; } SetState(STATE_FILTERSNAPSHOTVALID, true); } if (messageFilterSnapshot != null) { IMessageFilter f; int count = messageFilterSnapshot.Length; Message m = Message.Create(msg.hwnd, msg.message, msg.wParam, msg.lParam); for (int i = 0; i < count; i++) { f = (IMessageFilter)messageFilterSnapshot[i]; bool filterMessage = f.PreFilterMessage(ref m); // make sure that we update the msg struct with the new result after the call to // PreFilterMessage. if (f is IMessageModifyAndFilter) { msg.hwnd = m.HWnd; msg.message = m.Msg; msg.wParam = m.WParam; msg.lParam = m.LParam; modified = true; } if (filterMessage) { // consider : m is by ref here, so the user can change it. But we // are discarding changes by not propagating to msg. Should we? filtered = true; break; } } } return filtered; } /// /// Message filtering routine that is called before dispatching a message. /// If this returns true, the message is already processed. If it returns /// false, the message should be allowed to continue through the dispatch /// mechanism. /// internal bool PreTranslateMessage(ref NativeMethods.MSG msg) { bool modified = false; if (ProcessFilters(ref msg, out modified)) { return true; } if (msg.message >= NativeMethods.WM_KEYFIRST && msg.message <= NativeMethods.WM_KEYLAST) { if (msg.message == NativeMethods.WM_CHAR) { int breakLParamMask = 0x1460000; // 1 = extended keyboard, 46 = scan code if ((int)msg.wParam == 3 && ((int)msg.lParam & breakLParamMask) == breakLParamMask) { // ctrl-brk // wParam is the key character, which for ctrl-brk is the same as ctrl-C. // So we need to go to the lparam to distinguish the two cases. // You might also be able to do this with WM_KEYDOWN (again with wParam=3) if (Debugger.IsAttached) { Debugger.Break(); } } } Control target = Control.FromChildHandleInternal(msg.hwnd); bool retValue = false; Message m = Message.Create(msg.hwnd, msg.message, msg.wParam, msg.lParam); if (target != null) { if (NativeWindow.WndProcShouldBeDebuggable) { // we don't want to do a catch in the debuggable case. // if (Control.PreProcessControlMessageInternal(target, ref m) == PreProcessControlState.MessageProcessed) { retValue = true; } } else { try { if (Control.PreProcessControlMessageInternal(target, ref m) == PreProcessControlState.MessageProcessed) { retValue = true; } } catch (Exception e) { OnThreadException(e); } } } else { // See if this is a dialog message -- this is for handling any native dialogs that are launched from // winforms code. This can happen with ActiveX controls that launch dialogs specificially // // first, get the first top-level window in the hierarchy. // IntPtr hwndRoot = UnsafeNativeMethods.GetAncestor(new HandleRef(null, msg.hwnd), NativeMethods.GA_ROOT); // if we got a valid HWND, then call IsDialogMessage on it. If that returns true, it's been processed // so we should return true to prevent Translate/Dispatch from being called. // if (hwndRoot != IntPtr.Zero && UnsafeNativeMethods.IsDialogMessage(new HandleRef(null, hwndRoot), ref msg)) { return true; } } msg.wParam = m.WParam; msg.lParam = m.LParam; if (retValue) { return true; } } return false; } ////// Revokes our component from the active component manager. Does /// nothing if there is no active component manager or we are /// already invoked. /// private void RevokeComponent() { if (componentManager != null && componentID != INVALID_ID) { int id = componentID; UnsafeNativeMethods.IMsoComponentManager msocm = componentManager; try { msocm.FRevokeComponent(id); if (Marshal.IsComObject(msocm)) { Marshal.ReleaseComObject(msocm); } } finally { componentManager = null; componentID = INVALID_ID; } } } ////// /// Sets the culture for this thread. /// ///internal void SetCulture(CultureInfo culture) { if (culture != null && culture.LCID != SafeNativeMethods.GetThreadLocale()) { SafeNativeMethods.SetThreadLocale(culture.LCID); } } private void SetState(int bit, bool value) { if (value) { threadState |= bit; } else { threadState &= (~bit); } } /////////////////////////////////////////////////////////////////////////////////////////////////////// /*************************************************************************************** * * IMsoComponent * ****************************************************************************************/ // Things to test in VS when you change this code: // - You can bring up dialogs multiple times (ie, the editor for TextBox.Lines -- ASURT 41876) // - Double-click DataFormWizard, cancel wizard (ASURT 41562) // - When a dialog is open and you switch to another application, when you switch // back to VS the dialog gets the focus (ASURT 38961) // - If one modal dialog launches another, they are all modal (ASURT 37154. Try web forms Table\Rows\Cell) // - When a dialog is up, VS is completely disabled, including moving and resizing VS. // - After doing all this, you can ctrl-shift-N start a new project and VS is enabled. /// /// /// Standard FDebugMessage method. /// Since IMsoComponentManager is a reference counted interface, /// MsoDWGetChkMemCounter should be used when processing the /// msodmWriteBe message. /// bool UnsafeNativeMethods.IMsoComponent.FDebugMessage(IntPtr hInst, int msg, IntPtr wparam, IntPtr lparam) { return false; } ////// /// Give component a chance to process the message pMsg before it is /// translated and dispatched. Component can do TranslateAccelerator /// do IsDialogMessage, modify pMsg, or take some other action. /// Return TRUE if the message is consumed, FALSE otherwise. /// bool UnsafeNativeMethods.IMsoComponent.FPreTranslateMessage(ref NativeMethods.MSG msg) { return PreTranslateMessage(ref msg); } ////// /// Notify component when app enters or exits (as indicated by fEnter) /// the state identified by uStateID (a value from olecstate enumeration). /// Component should take action depending on value of uStateID /// (see olecstate comments, above). /// /// Note: If n calls are made with TRUE fEnter, component should consider /// the state to be in effect until n calls are made with FALSE fEnter. /// /// Note: Components should be aware that it is possible for this method to /// be called with FALSE fEnter more times than it was called with TRUE /// fEnter (so, for example, if component is maintaining a state counter /// (incremented when this method is called with TRUE fEnter, decremented /// when called with FALSE fEnter), the counter should not be decremented /// for FALSE fEnter if it is already at zero.) /// void UnsafeNativeMethods.IMsoComponent.OnEnterState(int uStateID, bool fEnter) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : OnEnterState(" + uStateID + ", " + fEnter + ")"); // Return if our (WINFORMS) Modal Loop is still running. if (ourModalLoop) { return; } if (uStateID == NativeMethods.MSOCM.msocstateModal) { // We should only be messing with windows we own. See the "ctrl-shift-N" test above. if (fEnter) { DisableWindowsForModalLoop(true, null); // WinFormsOnly = true } else { EnableWindowsForModalLoop(true, null); // WinFormsOnly = true } } } ////// /// Notify component when the host application gains or loses activation. /// If fActive is TRUE, the host app is being activated and dwOtherThreadID /// is the ID of the thread owning the window being deactivated. /// If fActive is FALSE, the host app is being deactivated and /// dwOtherThreadID is the ID of the thread owning the window being /// activated. /// Note: this method is not called when both the window being activated /// and the one being deactivated belong to the host app. /// void UnsafeNativeMethods.IMsoComponent.OnAppActivate(bool fActive, int dwOtherThreadID) { } ////// /// Notify the active component that it has lost its active status because /// the host or another component has become active. /// void UnsafeNativeMethods.IMsoComponent.OnLoseActivation() { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : Our component is losing activation."); } ////// /// Notify component when a new object is being activated. /// If pic is non-NULL, then it is the component that is being activated. /// In this case, fSameComponent is TRUE if pic is the same component as /// the callee of this method, and pcrinfo is the reg info of pic. /// If pic is NULL and fHostIsActivating is TRUE, then the host is the /// object being activated, and pchostinfo is its host info. /// If pic is NULL and fHostIsActivating is FALSE, then there is no current /// active object. /// /// If pic is being activated and pcrinfo->grf has the /// olecrfExclusiveBorderSpace bit set, component should hide its border /// space tools (toolbars, status bars, etc.); /// component should also do this if host is activating and /// pchostinfo->grfchostf has the olechostfExclusiveBorderSpace bit set. /// In either of these cases, component should unhide its border space /// tools the next time it is activated. /// /// if pic is being activated and pcrinfo->grf has the /// olecrfExclusiveActivation bit is set, then pic is being activated in /// "ExclusiveActive" mode. /// Component should retrieve the top frame window that is hosting pic /// (via pic->HwndGetWindow(olecWindowFrameToplevel, 0)). /// If this window is different from component's own top frame window, /// component should disable its windows and do other things it would do /// when receiving OnEnterState(olecstateModal, TRUE) notification. /// Otherwise, if component is top-level, /// it should refuse to have its window activated by appropriately /// processing WM_MOUSEACTIVATE (but see WM_MOUSEACTIVATE NOTE, above). /// Component should remain in one of these states until the /// ExclusiveActive mode ends, indicated by a future call to /// OnActivationChange with ExclusiveActivation bit not set or with NULL /// pcrinfo. /// void UnsafeNativeMethods.IMsoComponent.OnActivationChange(UnsafeNativeMethods.IMsoComponent component, bool fSameComponent, int pcrinfo, bool fHostIsActivating, int pchostinfo, int dwReserved) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : OnActivationChange"); } ////// /// Give component a chance to do idle time tasks. grfidlef is a group of /// bit flags taken from the enumeration of oleidlef values (above), /// indicating the type of idle tasks to perform. /// Component may periodically call IOleComponentManager::FContinueIdle; /// if this method returns FALSE, component should terminate its idle /// time processing and return. /// Return TRUE if more time is needed to perform the idle time tasks, /// FALSE otherwise. /// Note: If a component reaches a point where it has no idle tasks /// and does not need FDoIdle calls, it should remove its idle task /// registration via IOleComponentManager::FUpdateComponentRegistration. /// Note: If this method is called on while component is performing a /// tracking operation, component should only perform idle time tasks that /// it deems are appropriate to perform during tracking. /// bool UnsafeNativeMethods.IMsoComponent.FDoIdle(int grfidlef) { if (idleHandler != null) { idleHandler(Thread.CurrentThread, EventArgs.Empty); } return false; } ////// /// Called during each iteration of a message loop that the component /// pushed. uReason and pvLoopData are the reason and the component private /// data that were passed to IOleComponentManager::FPushMessageLoop. /// This method is called after peeking the next message in the queue /// (via PeekMessage) but before the message is removed from the queue. /// The peeked message is passed in the pMsgPeeked param (NULL if no /// message is in the queue). This method may be additionally called when /// the next message has already been removed from the queue, in which case /// pMsgPeeked is passed as NULL. /// Return TRUE if the message loop should continue, FALSE otherwise. /// If FALSE is returned, the component manager terminates the loop without /// removing pMsgPeeked from the queue. /// bool UnsafeNativeMethods.IMsoComponent.FContinueMessageLoop(int reason, int pvLoopData, NativeMethods.MSG[] msgPeeked) { bool continueLoop = true; // If we get a null message, and we have previously posted the WM_QUIT message, // then someone ate the message... // if (msgPeeked == null && GetState(STATE_POSTEDQUIT)) { Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : Abnormal loop termination, no WM_QUIT received"); continueLoop = false; } else { switch (reason) { case NativeMethods.MSOCM.msoloopFocusWait: // For focus wait, check to see if we are now the active application. // int pid; SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(null, UnsafeNativeMethods.GetActiveWindow()), out pid); if (pid == SafeNativeMethods.GetCurrentProcessId()) { continueLoop = false; } break; case NativeMethods.MSOCM.msoloopModalAlert: case NativeMethods.MSOCM.msoloopModalForm: // For modal forms, check to see if the current active form has been // dismissed. If there is no active form, then it is an error that // we got into here, so we terminate the loop. // if (currentForm == null || currentForm.CheckCloseDialog(false)) { continueLoop = false; } break; case NativeMethods.MSOCM.msoloopDoEvents: case NativeMethods.MSOCM.msoloopDoEventsModal: // For DoEvents, just see if there are more messages on the queue. // if (!UnsafeNativeMethods.PeekMessage(ref tempMsg, NativeMethods.NullHandleRef, 0, 0, NativeMethods.PM_NOREMOVE)) { continueLoop = false; } break; } } return continueLoop; } ////// /// Called when component manager wishes to know if the component is in a /// state in which it can terminate. If fPromptUser is FALSE, component /// should simply return TRUE if it can terminate, FALSE otherwise. /// If fPromptUser is TRUE, component should return TRUE if it can /// terminate without prompting the user; otherwise it should prompt the /// user, either 1.) asking user if it can terminate and returning TRUE /// or FALSE appropriately, or 2.) giving an indication as to why it /// cannot terminate and returning FALSE. /// bool UnsafeNativeMethods.IMsoComponent.FQueryTerminate(bool fPromptUser) { return true; } ////// /// Called when component manager wishes to terminate the component's /// registration. Component should revoke its registration with component /// manager, release references to component manager and perform any /// necessary cleanup. /// void UnsafeNativeMethods.IMsoComponent.Terminate() { if (this.messageLoopCount > 0 && !(ComponentManager is ComponentManager)) { this.messageLoopCount--; } Dispose(false); } ////// /// Called to retrieve a window associated with the component, as specified /// by dwWhich, a olecWindowXXX value (see olecWindow, above). /// dwReserved is reserved for future use and should be zero. /// Component should return the desired window or NULL if no such window /// exists. /// IntPtr UnsafeNativeMethods.IMsoComponent.HwndGetWindow(int dwWhich, int dwReserved) { return IntPtr.Zero; } } ////// This class allows us to handle sends/posts in our winformssynchcontext on the correct thread via /// control.invoke(). /// ///internal sealed class MarshalingControl : Control { internal MarshalingControl() : base(false) { Visible = false; SetState2(STATE2_INTERESTEDINUSERPREFERENCECHANGED, false); SetTopLevel(true); CreateControl(); CreateHandle(); } protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; // Message only windows are cheaper and have fewer issues than // full blown invisible windows. But, they are only supported // on NT. if (Environment.OSVersion.Platform == PlatformID.Win32NT) { cp.Parent = (IntPtr)NativeMethods.HWND_MESSAGE; } return cp; } } protected override void OnLayout(LayoutEventArgs levent) { } protected override void OnSizeChanged(EventArgs e) { // don't do anything here -- small perf game of avoiding layout, etc. } } /// /// /// This class embodies our parking window, which we create when the /// first message loop is pushed onto the thread. /// ///internal sealed class ParkingWindow : ContainerControl, IArrangedElement { // WHIDBEY CHANGES // in whidbey we now aggressively tear down the parking window // when the last control has been removed off of it. // // private const int WM_CHECKDESTROY = NativeMethods.WM_USER + 0x01; private int childCount = 0; [ SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters") // The parking window is invisible. // So we don't have to localize its Text. ] public ParkingWindow() { SetState2(STATE2_INTERESTEDINUSERPREFERENCECHANGED, false); SetState(STATE_TOPLEVEL, true); Text = "WindowsFormsParkingWindow"; Visible = false; } protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; // Message only windows are cheaper and have fewer issues than // full blown invisible windows. But, they are only supported // on NT. if (Environment.OSVersion.Platform == PlatformID.Win32NT) { cp.Parent = (IntPtr)NativeMethods.HWND_MESSAGE; } return cp; } } internal override void AddReflectChild() { if (childCount < 0) { Debug.Fail("How did parkingwindow childcount go negative???"); childCount = 0; } childCount++; } internal override void RemoveReflectChild() { childCount--; if (childCount < 0) { Debug.Fail("How did parkingwindow childcount go negative???"); childCount = 0; } if (childCount == 0) { if (IsHandleCreated) { //check to see if we are running on the thread that owns the parkingwindow. //if so, we can destroy immediately. //This is important for scenarios where apps leak controls until after the //messagepump is gone and then decide to clean them up. We should clean //up the parkingwindow in this case and a postmessage won't do it. int lpdwProcessId; //unused int id = SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(this, HandleInternal), out lpdwProcessId); Application.ThreadContext ctx = Application.ThreadContext.FromId(id); //We only do this if the ThreadContext tells us that we are currently //handling a window message. if (ctx == null || !Object.ReferenceEquals(ctx, Application.ThreadContext.FromCurrent())) { UnsafeNativeMethods.PostMessage(new HandleRef(this, HandleInternal), WM_CHECKDESTROY, IntPtr.Zero, IntPtr.Zero); } else { CheckDestroy(); } } } } private void CheckDestroy() { if (childCount == 0) { IntPtr hwndChild = UnsafeNativeMethods.GetWindow(new HandleRef(this, Handle), NativeMethods.GW_CHILD); if (hwndChild == IntPtr.Zero) { DestroyHandle(); } } } public void Destroy() { DestroyHandle(); } /// /// "Parks" the given HWND to a temporary HWND. This allows WS_CHILD windows to /// be parked. /// internal void ParkHandle(HandleRef handle) { if (!IsHandleCreated) { CreateHandle(); } UnsafeNativeMethods.SetParent(handle, new HandleRef(this, Handle)); } ////// "Unparks" the given HWND to a temporary HWND. This allows WS_CHILD windows to /// be parked. /// internal void UnparkHandle(HandleRef handle) { if (IsHandleCreated) { Debug.Assert(UnsafeNativeMethods.GetParent(handle) != Handle, "Always set the handle's parent to someone else before calling UnparkHandle"); // If there are no child windows in this handle any longer, destroy the parking window. CheckDestroy(); } } // Do nothing on layout to reduce the calls into the LayoutEngine while debugging. protected override void OnLayout(LayoutEventArgs levent) {} void IArrangedElement.PerformLayout(IArrangedElement affectedElement, string affectedProperty) {} protected override void WndProc(ref Message m) { if (m.Msg != NativeMethods.WM_SHOWWINDOW) { base.WndProc(ref m); if (m.Msg == NativeMethods.WM_PARENTNOTIFY) { if (NativeMethods.Util.LOWORD((int)m.WParam) == NativeMethods.WM_DESTROY) { UnsafeNativeMethods.PostMessage(new HandleRef(this, Handle), WM_CHECKDESTROY, IntPtr.Zero, IntPtr.Zero); } } else if (m.Msg == WM_CHECKDESTROY) { CheckDestroy(); } } } } ////// /// This class enables or disables all windows in the current thread. We use this to /// disable other windows on the thread when a modal dialog is to be shown. It can also /// be used to dispose all windows in a thread, which we do before returning from a message /// loop. /// ///private sealed class ThreadWindows { private IntPtr[] windows; private int windowCount; private IntPtr activeHwnd; private IntPtr focusedHwnd; internal ThreadWindows previousThreadWindows; private bool onlyWinForms = true; internal ThreadWindows(bool onlyWinForms) { windows = new IntPtr[16]; this.onlyWinForms = onlyWinForms; UnsafeNativeMethods.EnumThreadWindows(SafeNativeMethods.GetCurrentThreadId(), new NativeMethods.EnumThreadWindowsCallback(this.Callback), NativeMethods.NullHandleRef); } private bool Callback(IntPtr hWnd, IntPtr lparam) { // We only do visible and enabled windows. Also, we only do top level windows. // Finally, we only include windows that are DNA windows, since other MSO components // will be responsible for disabling their own windows. // if (SafeNativeMethods.IsWindowVisible(new HandleRef(null, hWnd)) && SafeNativeMethods.IsWindowEnabled(new HandleRef(null, hWnd))) { bool add = true; if (onlyWinForms) { Control c = Control.FromHandleInternal(hWnd); if (c == null) add = false; } if (add) { if (windowCount == windows.Length) { IntPtr[] newWindows = new IntPtr[windowCount * 2]; Array.Copy(windows, 0, newWindows, 0, windowCount); windows = newWindows; } windows[windowCount++] = hWnd; } } return true; } // Disposes all top-level Controls on this thread internal void Dispose() { for (int i = 0; i < windowCount; i++) { IntPtr hWnd = windows[i]; if (UnsafeNativeMethods.IsWindow(new HandleRef(null, hWnd))) { Control c = Control.FromHandleInternal(hWnd); if (c != null) { c.Dispose(); } } } } // Enables/disables all top-level Controls on this thread internal void Enable(bool state) { if (!onlyWinForms && !state) { activeHwnd = UnsafeNativeMethods.GetActiveWindow(); Control activatingControl = Application.ThreadContext.FromCurrent().ActivatingControl; if (activatingControl != null) { focusedHwnd = activatingControl.Handle; } else { focusedHwnd = UnsafeNativeMethods.GetFocus(); } } for (int i = 0; i < windowCount; i++) { IntPtr hWnd = windows[i]; Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : Changing enabled on window: " + hWnd.ToString() + " : " + state.ToString()); if (UnsafeNativeMethods.IsWindow(new HandleRef(null, hWnd))) SafeNativeMethods.EnableWindow(new HandleRef(null, hWnd), state); } // VSWhidbey 258748 :OpenFileDialog is not returning the focus the way other dialogs do. // Important that we re-activate the old window when we are closing // our modal dialog. // // VS Whidbey 337882: edit mode forever with Excel application // But, DON'T dink around with other people's state when we're simply // responding to external MSOCM events about modality. When we are, // we are created with a TRUE for onlyWinForms. if (!onlyWinForms && state) { if (activeHwnd != IntPtr.Zero && UnsafeNativeMethods.IsWindow(new HandleRef(null, activeHwnd))) { UnsafeNativeMethods.SetActiveWindow(new HandleRef(null, activeHwnd)); } if (focusedHwnd != IntPtr.Zero && UnsafeNativeMethods.IsWindow(new HandleRef(null, focusedHwnd))) { UnsafeNativeMethods.SetFocus(new HandleRef(null, focusedHwnd)); } } } } private class ModalApplicationContext : ApplicationContext { private ThreadContext parentWindowContext; private delegate void ThreadWindowCallback(ThreadContext context, bool onlyWinForms); public ModalApplicationContext(Form modalForm) : base(modalForm) { } public void DisableThreadWindows(bool disable, bool onlyWinForms) { Control parentControl = null; // VSWhidbey 400973 get ahold of the parent HWND -- if it's a different thread we need to do // do the disable over there too. Note we only do this if we're parented by a Windows Forms // parent. // if (MainForm != null && MainForm.IsHandleCreated) { // get ahold of the parenting control // IntPtr parentHandle = UnsafeNativeMethods.GetWindowLong(new HandleRef(this, MainForm.Handle), NativeMethods.GWL_HWNDPARENT); parentControl = Control.FromHandleInternal(parentHandle); if (parentControl != null && parentControl.InvokeRequired) { parentWindowContext = GetContextForHandle(new HandleRef(this, parentHandle)); } else { parentWindowContext = null; } } // if we got a thread context, that means our parent is in a different thread, make the call on that thread. // if (parentWindowContext != null) { // in case we've already torn down, ask the context for this. // if (parentControl == null) { parentControl = parentWindowContext.ApplicationContext.MainForm; } if (disable) { parentControl.Invoke(new ThreadWindowCallback(DisableThreadWindowsCallback), new object[]{parentWindowContext, onlyWinForms}); } else { parentControl.Invoke(new ThreadWindowCallback(EnableThreadWindowsCallback), new object[]{parentWindowContext, onlyWinForms}); } } } private void DisableThreadWindowsCallback(ThreadContext context, bool onlyWinForms) { context.DisableWindowsForModalLoop(onlyWinForms, this); } private void EnableThreadWindowsCallback(ThreadContext context, bool onlyWinForms) { context.EnableWindowsForModalLoop(onlyWinForms, this); } protected override void ExitThreadCore() { // do nothing... modal dialogs exit by setting dialog result } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Triplet.cs
- SystemFonts.cs
- TreeViewBindingsEditorForm.cs
- MobileComponentEditorPage.cs
- MediaTimeline.cs
- HtmlSelect.cs
- Policy.cs
- SimpleApplicationHost.cs
- CacheChildrenQuery.cs
- ReachSerializationUtils.cs
- ExtendedProperty.cs
- FixedSOMLineRanges.cs
- MenuItem.cs
- TextTreeInsertElementUndoUnit.cs
- ToolZoneDesigner.cs
- EncodingTable.cs
- OlePropertyStructs.cs
- SynchronousReceiveElement.cs
- exports.cs
- CodeVariableDeclarationStatement.cs
- ReflectEventDescriptor.cs
- SourceFileInfo.cs
- DataGridViewMethods.cs
- PerformanceCounterManager.cs
- XmlHelper.cs
- Zone.cs
- ScriptRegistrationManager.cs
- EnumDataContract.cs
- HttpResponse.cs
- AutomationPeer.cs
- SocketInformation.cs
- DataObjectFieldAttribute.cs
- Camera.cs
- DbConvert.cs
- KeyBinding.cs
- FolderLevelBuildProvider.cs
- FontFamily.cs
- SocketInformation.cs
- SqlNode.cs
- PackageDigitalSignatureManager.cs
- NotificationContext.cs
- AddInEnvironment.cs
- TagNameToTypeMapper.cs
- IconConverter.cs
- BrowserCapabilitiesFactoryBase.cs
- BaseAutoFormat.cs
- Accessors.cs
- Compiler.cs
- ComponentCollection.cs
- PromptStyle.cs
- XmlDesigner.cs
- MatchingStyle.cs
- ISAPIRuntime.cs
- UserPersonalizationStateInfo.cs
- WebServiceData.cs
- FlowLayout.cs
- TypeReference.cs
- InkCanvasSelection.cs
- ObjectContextServiceProvider.cs
- BitmapDecoder.cs
- ActivitySurrogateSelector.cs
- TreeNodeEventArgs.cs
- ConfigXmlWhitespace.cs
- ResXDataNode.cs
- WorkflowClientDeliverMessageWrapper.cs
- DataObjectFieldAttribute.cs
- Binding.cs
- ScriptingRoleServiceSection.cs
- DoubleCollection.cs
- EntityDataSourceValidationException.cs
- ListItemParagraph.cs
- HostedBindingBehavior.cs
- PackageFilter.cs
- SoapFault.cs
- DataGridViewBindingCompleteEventArgs.cs
- DataGridColumnDropSeparator.cs
- RectKeyFrameCollection.cs
- XmlException.cs
- PathSegment.cs
- XmlSchemaAll.cs
- OutputWindow.cs
- AdapterUtil.cs
- ObjectDataSourceView.cs
- ImpersonateTokenRef.cs
- EditorZoneBase.cs
- CodeStatementCollection.cs
- oledbmetadatacollectionnames.cs
- DataReaderContainer.cs
- WindowsTooltip.cs
- TextViewBase.cs
- ForeignConstraint.cs
- DataBinder.cs
- PropertyIDSet.cs
- GenericIdentity.cs
- MILUtilities.cs
- XsdBuildProvider.cs
- RouteItem.cs
- MsmqIntegrationBindingElement.cs
- NavigationWindow.cs
- WebPartMenuStyle.cs