单个进程 winform 应用程序上的多个应用程序域

Posted

技术标签:

【中文标题】单个进程 winform 应用程序上的多个应用程序域【英文标题】:Multiple app domains on a single process winform application 【发布时间】:2012-02-24 07:13:47 【问题描述】:

我正在使用 program.cs 文件中的此代码在我的 winform 应用程序中创建应用程序域

static class Program

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    ///

    [STAThread]
    static void Main(string[] args)
    
        string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value.ToString();

        // unique id for global mutex - Global prefix means it is global to the machine
        string mutexId = string.Format("Global\\0", appGuid);

        using (var mutex = new Mutex(false, mutexId))
        
            var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
            var securitySettings = new MutexSecurity();
            securitySettings.AddAccessRule(allowEveryoneRule);
            mutex.SetAccessControl(securitySettings);


            if (mutex.WaitOne(TimeSpan.Zero, true) || (args.Length > 0 && string.Compare(args[0], "secondary", true) == 0))
            
                ErrorHandler errorHandler = new ErrorHandler();
                DffEnvironment.Default.AppErrorHandler = errorHandler;
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(errorHandler.Application_ErrorHandler);
                MainForm mainForm = new MainForm();
                DffEnvironment.Default.MainForm = mainForm;
                if (args.Length > 0)
                
                    MessageBox.Show(" CurrentDomain" + AppDomain.CurrentDomain.FriendlyName);
                
                Application.Run(mainForm);
            
            else
            
                // send our Win32 message to make the currently running instance
                // Add new app domain
                NativeMethods.PostMessage(
                    (IntPtr)NativeMethods.HWND_BROADCAST,
                    NativeMethods.WM_SHOWME,
                    IntPtr.Zero,
                    IntPtr.Zero);
            
        
    

在我的 MainForm (Form) 中我重写了代码 WndProc 方法并写了这个

static int procNumber=0;
protected override void WndProc(ref System.Windows.Forms.Message m)
        
            if (m.Msg == NativeMethods.WM_SHOWME)
            
                try
                    
                        procNumber++;
                        AppDomain appDomain = AppDomain.CreateDomain("MyAppDomainApplication" + procNumber.ToString(), null, setupInfo);
                        string[] arguments =  "secondary" ;
                        appDomain.ExecuteAssembly("MyAppDomainApplication.exe", null, arguments);
                    
                    catch (Exception ex)
                    
                        MessageBox.Show(ex.ToString());
                    
                
            
            base.WndProc(ref m);
        

它工作正常,当我尝试打开我的应用程序时,它会在已运行的同一进程中创建另一个应用程序域。

我的第一个问题是我可以创建已经从其他用户运行的同一进程的应用程序域,例如

John 正在开发这个应用程序并拥有两个应用程序域和一个进程。 Steve 在同一台机器上登录并尝试打开此应用程序,该应用程序不应该创建进程,它应该在 John 已经运行的进程中添加新的应用程序域。

我通过在互斥锁名称前加上“Global\”前缀检测到在另一个用户中运行的进程。如上所述here

当我在 program.cs 中编辑以下代码时,第二个问题就在这里

NativeMethods.PostMessage(
                        (IntPtr)NativeMethods.HWND_BROADCAST,
                        NativeMethods.WM_SHOWME,
                        IntPtr.Zero,
                        IntPtr.Zero);

try

    procNumber++;
    AppDomain appDomain = AppDomain.CreateDomain("MyAppDomainApplication" + procNumber.ToString(), null, setupInfo);
    string[] arguments =  "secondary" ;
    appDomain.ExecuteAssembly("MyAppDomainApplication.exe", null, arguments);
 
 catch (Exception ex)
 
    MessageBox.Show(ex.ToString());
 

它创建了另一个进程,为什么它在 Program.cs 文件中不起作用,为什么我必须向我的表单发送消息并在 WndProc 方法中做同样的事情

【问题讨论】:

为什么需要单例进程?你想达到什么目的? 【参考方案1】:

我会回答你的第二个问题。

应用程序域是进程内部的隔离环境。这里有两个进程,它们都有自己的应用程序域。如果要命令另一个进程创建新的应用程序域,则必须从一个进程向另一个进程发送消息。这就是你必须发送消息的原因。

我还怀疑代码没有按您预期的方式工作。 ExecuteAssembly() 与主用户界面在同一线程中运行。如果执行的程序集开始一个新的消息循环,您的调用堆栈将在每个 WM_SHOWME 消息后增长,最终您将获得堆栈溢出异常。

在这种情况下,您的调用堆栈将大致如下所示:

at Application.Run()
at Main()
at AppDomain.ExecuteAssembly()
...
at Application.Run()
at Main()
at AppDomain.ExecuteAssembly()
at Application.Run()
at Main()

【讨论】:

是的,我可以理解,但我可以在 WndProc 方法中检查是否应该在这种情况下调用它。我设法做到了。我想知道的是有什么方法可以让应用程序域出现在 program.cs 文件中。

以上是关于单个进程 winform 应用程序上的多个应用程序域的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中为多个进程提供单个命令窗口

将 .NET 类限制为计算机边界上的单个对象实例 =>“进程间单例”

c#:具有多个应用程序域的单个进程 VS 多个进程

c# winform 获取当前程序运行根目录

并发编程之 进程

静态对象/多个应用程序域/一个进程