[Mono-dev] Emedding mono: System.Windows.Form trouble

Guy Sherman guy at guysherman.com
Thu Mar 3 05:09:54 EST 2011


Hi,

 

I'm working on a sandbox game engine, with mono as the scripting language.
Tonight I got it to attach a DirectX rendering context to a Windows Forms
window created by some .NET code running in mono.

 

I have injected two methods into the runtime:

 

void Renderer::RegisterScriptingInterface()
{
                mono_add_internal_call ("RendererServices::CreateRenderer",
Renderer::CreateRenderer);
                mono_add_internal_call ("RendererServices::RendererDraw",
Renderer::RendererDraw);
}

 

 

and have wrapped them appropriately in a C# class with externs, and they
work.

 

Now, I naively thought that I could spin up a window, and have a timer
calling Invalidate(), with an overridden paint which calls RendererDraw
above. The problem is that my timer does not seem to fire. Paint is working
because it calls draw once, and also sometimes when I resize the window (so
when it is invalidated it calls my overridden paint which calls my c++
code).

 

I then tried setting up a thread in the Form's Load method, which
continuously calls RendererDraw, but again, it does not seem to work. The
partial class for my form is below.

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

 
namespace TestPlugin
{
    public partial class MainForm : Form
    {
        private Thread t;
        
        public MainForm()
        {
            InitializeComponent();
            //timer1.Enabled = true;
            //timer1.Start();

            
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            Invalidate();
            RendererServices.RendererDraw(this.Handle);
        }

        private void MainForm_Paint(object sender, PaintEventArgs e)
        {
            RendererServices.RendererDraw(this.Handle);
        }

        private void drawRepeatedly()
        {
            while (true)
            {
                RendererServices.RendererDraw(this.Handle);
            }

        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            t = new Thread(new ThreadStart(drawRepeatedly));
            t.Start();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            RendererServices.RendererDraw(this.Handle);
        }

        private void MainForm_DoubleClick(object sender, EventArgs e)
        {

        }

        private void MainForm_Click(object sender, EventArgs e)
        {
            RendererServices.RendererDraw(this.Handle);
        }
    }
}

 

You can probably see that I also tried hooking up the on-click event, and a
button. The button didn't show up (probably because I gave the window handle
to DirectX), but the click event didn't seem to be getting raised (although
I wonder if this is because I gave the handle to DirectX. I also tried (but
haven't copied the source) giving DirectX the handle of a panel instead of
the window itself, but still no dice.

 

I'm not expecting a whole lot of help on the DirectX side, but I'm just
wondering if there is something special to do with the UI thread etc when
running a Windows Forms window via the mono embedding api.

 

Oh yeah, the window is created by another piece of .net code.

 

public class PluginHost
    {
        private MainForm mainForm;
        
        public void Start()
        {
            mainForm = new MainForm();
            mainForm.Show();
            
        }
    }

 

which is itself called via the embedding api as follows (not the actual code
but you get the idea).

 

int main()

{

// some stuff

 

mono_config_parse (NULL);

domain = mono_jit_init (file);
assembly = mono_domain_assembly_open(domain, file);
image = mono_assembly_get_image(assembly);

 

// Then I register my internal calls as above

 

//I use a generated wrapper class to construct the PluginHost and call Start
but it boils down to

result = mono_object_new( this->domain, this->me /* the MonoImage* */ );

mono_runtime_object_init( result );

 

mono_runtime_invoke( this->StartMonoMethod, target, args, NULL );  

 

// more stuff

}

 

The program then continues on to process the main event loop of the C++ side
of things.

 

Do I need to call the mono_runtime_invoke above in its own thread, and in my
PluginHost class do an Application.Run(mainForm)?

 

 


Thanks in advance for your help.

 

Guy.

 

Guy Sherman

web: http://www.guysherman.com

email: guy at guysherman.com

phone: +64 21 355 190

 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.ximian.com/pipermail/mono-devel-list/attachments/20110303/b592cfc1/attachment-0001.html 


More information about the Mono-devel-list mailing list