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

本文关键字:打开对话框 出错 线程 API Mono 启动 新线程 使用 | 更新日期: 2023-09-27 17:53:44

我正在编写一个用c++编写的本机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()

现在,在开始时,表单打开,它工作(没有冻结在屏幕上,因为它在自己的线程中运行),我可以通过在提示符下输入"open"打开表单的更多实例。只有当我关闭所有打开的表单,然后试图打开一个新表单时(在关闭所有打开的表单后再次输入"open"),才会抛出异常。

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

你能帮我解密这条信息吗?:)

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

下面是我使用的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;
}

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

在研究了很多之后,我可以放心地说这是Mono的一个bug。我已经提交了关于这个问题的bug报告。

对于C API来说,这不是一个问题,因为我能够仅在c#代码中重新创建错误。当在一个新线程上第一次打开一个表单时,Mono似乎做了一些初始化工作。如果该线程停止运行或耗尽,则会丢失某些引用,此后打开表单或对话框的任何调用都将失败。