[Mono-osx] Invoke CIL/Managed Code from ObjC/XCode on Mac

Duane Wandless duane at wandless.net
Sat Oct 25 09:22:38 EDT 2008


I will share what works for me.  First I use monobjc<http://www.monobjc.net/>.
Great documentation.  Easy to use.  Well supported.   I am using the latest
mono install 2.0, though this worked with 1.9 as well.  And I use Xcode
3.1.  I place my mono EXE in build/Debug/MyCocoa.app/Content/Libraries,
along with the Monobjc DLLs.  As you will see in the code (main.m) below, I
load the EXE relative to the app bundle location.

For me anyway I hit a bug in 2.0 that required me to load an EXE rather than
a DLL.  In some ways the EXE is better.  I have a Program.cs (see below)
that initializes the MonoObjc environment.  It is important to load the
MonoObjc environment prior to Cocoa setting up the IB references.  This way
when the NIB file is loaded it will find your [ObjectiveCClass] references,
see MainForm.cs below, which is snippets only.

In my NIB file I have an object that has its class MonoMessage.  I hookup
the array, tree, outline view, fields, etc to this object.  At runtime they
are hooked up to my mono class.  I have some objC code (MainDocument.m
below) that sends messages to my mono class.  And my mono class sends
messages back to the objC world.

We wanted the best of both worlds.  The power of C# and the ability to reuse
the code on Mac and Windows.  But we also wanted the native build
environment for the Leopard frontend.  So not only was using IB a
requirement but so was writing the UI code in objC.  Thanks to mono and
monobjc we accomplished this with a very clean environment.

You can also take the mono EXE and fully embed it within the cocoa app.
This way the end user is not required to install mono.  But that is a topic
for a different thread.


   - Other C Flags = -D_THREAD_SAFE -D_REENTRANT
   -I/Library/Frameworks/Mono.framework/Versions/2.0/include/mono-1.0
   -I/Library/Frameworks/Mono.framework/Versions/2.0/include/glib-2.0
   -I/Library/Frameworks/Mono.framework/Versions/2.0/lib/glib-2.0/include
   - Other C++ Flags = $(OTHER_CFLAGS)
   - OTHER_LDFLAGS = -pthread
   -L/Library/Frameworks/Mono.framework/Versions/Current/lib -lmono -lpthread
   -lm -lgthread-2.0 -lglib-2.0 -lintl -rpath at loader_path/../Libraries



main.m:
#import <Cocoa/Cocoa.h>
#include <mono/jit/jit.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/mono-config.h>

int main(int argc, char *argv[])
{
    NSAutoreleasePool *pool;
    pool = [[NSAutoreleasePool alloc] init];

    MonoDomain *domain;
    NSString *libraryPath = [[[NSBundle mainBundle] bundlePath]
stringByAppendingPathComponent:@"Contents/Libraries"];
    NSString *sampleAssemblyPath = [libraryPath
stringByAppendingPathComponent:@"MacMonoClient.exe"];
    NSLog(@"libraryPath: %@", sampleAssemblyPath);
    mono_config_parse ("config");
    domain = mono_jit_init ([sampleAssemblyPath UTF8String]);
    MonoAssembly *monoAssembly = mono_domain_assembly_open(domain,
[sampleAssemblyPath UTF8String]);
    mono_jit_exec (domain, monoAssembly, 1, argv);
    NSLog(@"sample assembly: %p", monoAssembly);
    [pool release];

    return NSApplicationMain(argc, (const char **) argv);
}

Program.cs:
using System;
using Monobjc;
using Monobjc.Cocoa;

namespace MacClient
{
    static class Program
    {
       public static void Main()
       {
            ObjectiveCRuntime.LoadFramework("Cocoa");
            ObjectiveCRuntime.LoadFramework("QTKit");
            ObjectiveCRuntime.Initialize();
       }
    }
}

MainForm.cs:
using System;
using Monobjc;
using Monobjc.Cocoa;
using Monobjc.QuickTime;

namespace MacClient
{
    [ObjectiveCClass("MonoMessage")]
    public class MyControl : NSObject
    {
        private static readonly Class ControllerClass =
Class.GetClassFromType(typeof(MyControl));

        public MyControl() { }
        public MyControl(IntPtr np) : base(np) { }

        NSAutoreleasePool pool = new NSAutoreleasePool();
        ~MyControl()
        {
            pool.Drain();
        }

        [ObjectiveCField]
        public NSArrayController projectsController;
        [ObjectiveCField("itemsController")]
        public NSTreeController folderContent;
        [ObjectiveCField]
        public NSOutlineView folderOutline;

        [ObjectiveCMessage("init")]
        public override Id Init()
        {
            ObjectiveCRuntime.SendMessageSuper<IntPtr>(this,
ControllerClass, "init");

NSNotificationCenter.DefaultCenter.AddObserverSelectorNameObject(this,
ObjectiveCRuntime.Selector("doAuth:"), "doAuth", null);
                 }
        [ObjectiveCMessage("awakeFromNib")]
        public void awakeFromNib()
        {
        }
        [ObjectiveCMessage("doAuth:")]
        public void SelectionChanged(NSNotification notification)
        {
            NSArray loginParms = notification.UserInfo.ObjectForKey(new
NSString("params")).CastTo<NSArray>();
            Login(loginParms[0].CastTo<NSString>(),
loginParms[1].CastTo<NSString>());
        }
    }
}

MainDocument.m
- (IBAction)login:(id)sender
{
    NSLog(@"Starting login process...");

    NSString *username = [usernameTextField stringValue];
    NSString *password = [passwordTextField stringValue];

    NSArray *loginParams = [NSArray arrayWithObjects:username, password,
nil];
    NSDictionary* dict =  [NSDictionary dictionaryWithObject:loginParams
forKey:@"params"];
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    [nc postNotificationName:@"doAuth" object:nil userInfo:dict];
}

On Fri, Oct 24, 2008 at 10:13 PM, Kevin Heeney <koheeney at gmail.com> wrote:

>    I think I have hit a wall.  I am fairly new to mono on mac; however am
> familiar with .NET and Objc/Cocoa.  I am unable to successfully 'embed mono'
> or call methods from my Mono dll in ObjC.  I have created a UI using
> Interface Builder and have my App Controller in ObjC ready to call my C# dll
> which contains my logic.  Cocoa# and ObjCSharp both claim to be 2 way
> bridges; however I can only find code for calling Cocoa from C# and not the
> other way around.  In addition, I cannot get the samples from <
> http://www.mono-project.com/Embedding_Mono> on Embedding Mono to work in
> XCode.  My actual issue with the latter is I cannot get XCode to link to the
> mono framework.  I am getting errors like "main.c:1: error:
> mono/jit/jit.h: No such file or directory".    I am not sure what I am
> missing; it may be simple.
>
> Any guidance would be appreciated.
> Thanks,
> Kevin
>
> _______________________________________________
> Mono-osx mailing list
> Mono-osx at lists.ximian.com
> http://lists.ximian.com/mailman/listinfo/mono-osx
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.ximian.com/pipermail/mono-osx/attachments/20081025/8e1aded6/attachment-0001.html 


More information about the Mono-osx mailing list