使用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++代码中,我做了以下操作:
- 加载程序集
- 找到start()方法并运行它
- 进入一个从控制台 读取输入的无限循环
- 当接收到输入字符串"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的一个bug。我已经提交了关于这个问题的bug报告。
对于C API来说,这不是一个问题,因为我能够仅在c#代码中重新创建错误。当在一个新线程上第一次打开一个表单时,Mono似乎做了一些初始化工作。如果该线程停止运行或耗尽,则会丢失某些引用,此后打开表单或对话框的任何调用都将失败。