使用Mono API启动新线程和打开对话框时出错

时间:2011-04-29 23:42:03

标签: c# c multithreading mono embedding

我正在使用C ++编写的Native dll,它使用mono来显示图形用户界面。我写了一个简单的骨架,它有效,但在某些条件下我得到了一个错误。

首先是我从Mono API调用的C#代码

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Threading;

namespace testApp
{
    static class Program
    {
        // This creates a new thread and runs dialog() on it, 
        // which opens a dialog window
        static void start()
        {
            Console.WriteLine("Running thread in Mono");
            Thread t = new Thread(new ThreadStart(dialog));
            t.Start();
        }

        public static void dialog()
        {
            Form f = new Form();
            f.ShowDialog();
            f.Dispose();
        }
    }
}

这会编译为testApp.dll

在我的C / C ++代码中,我执行以下操作:

  1. 加载程序集
  2. 找到start()方法并运行它
  3. 进入无限循环,从控制台
  4. 读取输入
  5. 当收到输入字符串“open”时,再次运行start()
  6. 现在,在开始时,表单打开,它可以工作(不会在屏幕上冻结,因为它在自己的线程中运行),我可以通过在提示符下键入“打开”来打开更多表单实例。 仅当我关闭所有打开的表单然后尝试打开一个新表单时才会抛出异常(在关闭所有打开的表单后再次键入“打开”)。

    Unhandled Exception: System.OutOfMemoryException: Not enough memory to complete operation [GDI+ status: OutOfMemory]
      at System.Drawing.GDIPlus.CheckStatus (Status status) [0x00000] in <filename unknown>:0
      at System.Drawing.Graphics.FromHwnd (IntPtr hwnd) [0x00000] in <filename unknown>:0
      at System.Windows.Forms.XplatUIWin32.GetAutoScaleSize (System.Drawing.Font font) [0x00000] in <filename unknown>:0
      at System.Windows.Forms.XplatUI.GetAutoScaleSize (System.Drawing.Font font) [0x00000] in <filename unknown>:0
      at System.Windows.Forms.Form.GetAutoScaleSize (System.Drawing.Font font) [0x00000] in <filename unknown>:0
      at System.Windows.Forms.Form..ctor () [0x00000] in <filename unknown>:0
      at (wrapper remoting-invoke-with-check) System.Windows.Forms.Form:.ctor ()
      at testApp.Program.dialog () [0x00000] in <filename unknown>:0
      at System.Threading.Thread.StartUnsafe () [0x00000] in <filename unknown>:0
    
    你可以帮我解密那条消息吗? :)

    不知何故,当我关闭最后一个表单窗口时,我猜单声道决定卸载/关闭一些关键组件,阻止我在该时间点之后打开另一个窗口。

    这是我使用的C ++(嗯,实际上是C)代码:

    #define _CRT_SECURE_NO_WARNINGS
    
    #include <mono/jit/jit.h>
    #include <mono/metadata/object.h>
    #include <mono/metadata/environment.h>
    #include <mono/metadata/assembly.h>
    #include <mono/metadata/debug-helpers.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    static void runThread(MonoDomain* domain, MonoAssembly* assembly)
    {
        MonoImage* image = mono_assembly_get_image (assembly);
    
        MonoClass *klass;
        MonoObject *obj;
        MonoMethod *m = NULL, *start = NULL;
        void* iter = NULL;
        klass = mono_class_from_name (image, "testApp", "Program");
    
        // Find method start()
        while ((m = mono_class_get_methods (klass, &iter))) 
        {
            if (strcmp (mono_method_get_name (m), "start") == 0) 
            {
                start = m;
                break;
            }
        }
    
        mono_runtime_invoke (start, NULL, NULL, NULL);
    }
    
    int main(int argc, char* argv[])
    {
        MonoDomain *domain;
        const char *file;
        int retval;
    
        if (argc < 2)
        {
            fprintf (stderr, "Please provide an assembly to load\n");
            return 1;
        }
    
        file = argv [1];
        domain = mono_jit_init (file);
        MonoAssembly *assembly;
        assembly = mono_domain_assembly_open (domain, file);
    
        if (!assembly)
        {
            printf("Can not load assembly");
            exit (2);
        }
    
        // open dialog
        runThread(domain, assembly);
    
        // endless loop
        char *p = new char[100];
        while(1)
        {
            gets (p);
    
            // Open another dialog
            if( strcmp(p, "open") == 0)
                runThread(domain, assembly);
        }
    
        retval = mono_environment_exitcode_get ();
        mono_jit_cleanup (domain);
        return retval;
    }
    

1 个答案:

答案 0 :(得分:1)

在研究这个问题之后,我可以肯定地说这是Mono中的一个错误。我已就此事提交了一份错误报告。

这不是C API的问题,因为我只能在C#代码中重新创建bug。在新线程上第一次打开表单时Mono似乎做了一些初始化工作。如果该线程停止运行或用完,那么一些丢失的引用,以及之后打开表单或对话框的任何调用都将失败。这是意外和不受欢迎的行为。