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

时间:2012-02-24 07:13:48

标签: c# appdomain

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

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正在开发此应用,并拥有两个应用领域和一个流程。史蒂夫登录同一台机器并试图打开这个应用程序,应用程序不应该创建进程,它应该在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 个答案:

答案 0 :(得分: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()