开发者

Error when starting a new thread and opening dialog using Mono API

I'm working on a Native dll written in C++ that uses mono to show a graphical user interface. I've written a simple skeleton, it works but I get an error under certain conditions.

First here is the C# code I'm calling from the Mono API

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();
        }
    }
}

This gets compiled as testApp.dll

In my C/C++ code I do the following:

  1. Load the assembly
  2. Locate the start() method and run it
  3. enter an endless loop that reads input from console
  4. when the input string "open" is received, run start() again

Now, at the beginning, the form opens, it works (doesn't freeze on screen as it's running in its own thread) and I can open more instances of the form by typing "open" at the prompt. An exception is thrown only when I close all open forms and then attempt to open a new one (typing "open" again after closing ALL opened forms).

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

Can you help me decrypt that message? :)

somehow, when I close the last form window, I guess mono decides to unload/shut down some critical component that prevents me from opening another window after that point in time.

Here is my C++ (well, C actually) code that I use:

#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;
}


AFter researching this a lot more I can safely say that this is a bug in Mono. I've submitted a bug report on the matter.

This was not a problem regarding the C API as I was able to recreate the bug in only C# code. When opening a form for the first time on a new thread Mono seems to do some initialization work. If that thread stops running or runs out, then some reference of whatever is lost, and any calls that open forms or dialogs after that will fail. This is unexpected and unwanted behavior.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜