Thread
Print

Mix Objective C with Mono

Mix Objective C with Mono

Here's an article on how to call Mono .Net class in the Objective C project.
We actually did this as described.
See this page for a quick start, but the last code segment on that page is wrong, because it's omitting the "--xcode"-parameter. http://monotouch.net/Documentation/XCode
What you have to do to embed your Mono-EXE/DLL into an Objective-C program is to compile your source with SharpDevelop, then run mtouch with these parameters:
Copy to clipboard
Code:
/Developer/MonoTouch/usr/bin/mtouch --linksdkonly --xcode=output_dir MyMonoAssembly.exe
This only works with the full version of MonoTouch. The trial does not allow to use the "--xcode"-argument . The "--linksdkonly"-argument is needed if you want mtouch to keep unreferenced classes in the compiled output, otherwise it strips unused code.

Then mtouch compiles your assembly into native ARM-code (file extension .s) and also generates a XCode template which loads the Mono-Runtime and your code inside the XCode/ObjC-program. You can now use this template right away and include your Obj-C-code or extract the runtime loading code from the "main.m"-file and insert it into your existing XCode-project. If you use an existing project you also have to copy all .exe/.dll/.s files from the xcode-output-dir that mtouch made.

Now you have your Mono-Runtime and assembly loaded in an XCode-project. To communicate with your assembly, you have to use the Mono-Embedding-API (not part of MonoTouch, but Mono). These are C-style API calls. For a good introduction see this page: h**p://www.mono-project.com/Embedding_Mono Also the Mono-Embedding-API documentation might be helpful: h**p://go-mono.com/docs/monodoc.ashx?tlink=root:/embed

What you have to do now in your Obj-C-code is to make Embedding-API calls. These steps might involve: Get the application domain, get the assembly, get the image of the assembly, locate the class you want to use, instantiate an object from that class, find methods in class, call methods on object, encapsulate method arguments in C-arrays and pass them to the method-call, get and extract method return values. There are examples for this on the embedding-api-doc-page above.

You just have to be careful with memory consumption of your library, as the mono runtime takes some memory as well.

So this is the way from Obj-C to C#. If you want to make calls from C#/Mono into your Obj-C-program, you have to use the MonoTouch-bindings, which are described here: h**p://monotouch.net/Documentation/Binding_New_Objective-C_Types You could also use pure C-method calls from the embedding/P/Invoke-API.

Hope this gets you started.

TOP

http://monotouch.net/Documentation/XCode

                                                Xcode                                       
                                                                                                                               
                                                                                        
                                                                                 Table of contents

RequirementsTo get started with MonoTouch and XCode you will need to install:
  • XCode from Apple
  • iPhone developer SDK from Apple
  • MonoTouch


Sanity CheckOnce you have the above, start XCode and create a simple shell that will contain Mono, this is done by following these steps:
  • From the File Menu, select New Project
  • Select in iPhone OS the "Window based application" option.
  • Select Run from the Run menu
The above should launch an empty application in the iPhone simulator.
Device Developers: If you are a registered iPhone developer, you will want to also test that the above application runs on the iPhone or the iPod Touch by changing the Active SDK from "Simulator- XX | Debug" to "Device - XX | Debug" where XX is the version of the SDK that you have installed. Make sure that this application works correctly before proceeding.


Using the MonoTouch FrameworkTo use MonoTouch with your existing Objective-C project, you need to use the MonoTouch Framework. Follow these steps to prepare your project:
  • Open your project and go to Project->Edit Project Settings and select the "Build" tab
  • Change the Configuration drop down to "All Configurations"
  • Add "/Developer/MonoTouch/SDKs/MonoTouch1.0.$(PLATFORM_NAME).sdk" to the "Additional SDKs" field
  • Add "-liconv -lmono -lmonotouch" to the "Other Linker Flags" field
  • Change the "Code Signing Resource Rules Path" to "$(SDKROOT)/ResourceRules.plist"


Embedding the SampleThe next step is to create a sample C# program that will drive your application, from the File menu create a new file, select "Other" and then "Empty file" and call this "simple.cs"
In this file put the following code:
using MonoTouch.UIKit;

class Sample {
    static void Main (string [] args)
    {
        UIApplication.Main (args);
    }
}You can compile the above program using the MonoTouch C# compiler, like this:
smcs simple.cs -r:monotouch.dllThe next is to embed Mono in your Objective-C code and to have the code call the C# code. The simplest thing is to get the basics generated by the mtouch tool, issue the following command:
$ mtouch simple.exeThe result of running the above command will produce a few files:
  • main.m: the source code to embed Mono in your Objective-C code.
  • *.s: various files that contain the ARM assembly code for your program and any of their dependencies.
  • Info.plist: a sample Info.plist that you can use
  • PkgInfo: a sample PkgInfo that you can use.
You must add all of the *.m and *.s files to your build.

TOP

http://www.mono-project.com/ObjCSharp

ObjCSharp        
         Introduction ObjC# is a two way bridge to leverage the CLR into the ObjectiveC programming language and expose your ObjectiveC classes to the CLR.  ObjC# is currently only support on Mac OS X.  There are a few simple rules to remember when translating a CLR method into a ObjC selector:
  • All method names with arguments are appended based on the argument type.  That is MyMethod (int a, float b) would become MyMethodWithInt32:Single:
  • The parameterless constructor are mapped to init
  • Constructors with parameters are mapped like methods but prefaced with init (eg; initWithInt32
You also need to remember that if your method is returning a primitive type it is returned as a pointer to the result; so if you had:
public int MyMethod () {
  return 1;
}Then your objc# code would be:
NSLog (*(int *)[yourinstance MyMethod]);
Tutorials The beginning of every ObjC# invokation involves initializing the bridge:
Allocate a new instance of the bridge:
ObjCSharpBridge bridge = [ObjCSharpBridge alloc];
Initialize the bridge:
[bridge init];
After you have a working instance of the bridge you need to load the assembly you wish to interact with:
[bridge loadAssembly: "test-library.dll"]
You are now ready to load a class representation of any class in the loaded assembly (or its referenced assemblies).
Class yourClass = [bridge getClass: "YourNameSpace.YourClass"];
If you wanted to call a static method; you do so directly on the class representation:
[yourClass YourStaticMethod];
You now of course need to initialize the class (mapped to the constructor in the CLR):
id instance = [yourClass initWithInt32:-2];
You may now call methods according to the rules stated above.
Make sure you look at the test/ directory in SVN for more examples of different code/call paths.
Versions & Status ObjC# is currently at v0.1 and only available from SVN.  It can successfully represent classes both ways across the bridge.  It can also invoke events through the bridge.  Marshalling of primitives works.

TOP

Scripting With Mono            Table of Contents1 Scripting

2 The Mono Offering

3 Scripting an Application

4 Game Developers

4.1 Performance
4.2 Language Support
4.3 Licensing


5 Continued Performance Increase

6 Using Mono in  your Application



                    
        by Miguel de Icaza
In this article we will discuss how you can use Mono to increase your productivity and make your software applications extensible without having to rewrite any of your existing C or C++ code into C#.
This technique has many names: application scripting, runtime hosting, runtime embedding.  They are all the same thing.
Scripting  In the past, software used to be written entirely in a single programming language.   Developers had to strike a balance between high performance and having to pick a low-level language or slower execution speed but using a high level language.
For example a C/C++ application would look like this:


A scripted language application would look like this:


Picking one or the other is a difficult choice as there are many nuances that software developers face.   The high-level languages are more productive and developers get more done for each line of code written.   But high-level languages come with a price, the software does not run as fast as it could and sometimes requires more cpu, more resources and in some markets might make the difference between a successful project or a failed project.
Developers have turned to scripting as a mechanism to balance the best of both worlds, the idea is simple.   The engine of the application is developed in C or C++ and usually maintained and developed by the veteran members of a team, while pieces of the UI, dialogs, interaction, or non-performance critical routines are written in a higher-level scripting language.   
The result looks like this:


This idea was for a long time championed by John Ousterhout.  You can read some of his discussions here (http://home.pacbell.net/ouster/scripting.html).
The following figure is a slightly updated version of John's figure:

From John Ousterhout's paper:
A comparison of various programming languages based on their level (higher level languages execute more machine instructions for each language statement) and their degree of typing.   System programming languages like C tend to be strongly typed and medium level (5-10 instructions/statement).  Scripting languages like Tcl tend to be weakly typed and very high-level (100-1000 instructions per statement). By using a high-level scripting language, developers are able to mix low-level code with high level code.   
Historically, developers have turned to different technologies to implement scripting, from the very simple "batch processing" languages, to evolutions of those (Tcl, the tool command language comes to mind) to some custom in-house developed languages (Second Life's LSL is a good example) to more mainstream languages like Lua, Perl or Python.
Some languages were designed with embedding in mind from the beginning (like Python) which makes embedding Python very simple.   Other languages are embeddable but the embedding API is not as clear as it could be, and mostly they expose the internals of the language and merely allow for the language to be embedded.
You can think of the speed of languages as a progression (and here am taking a few liberties, but this is just for illustration purposes), roughly it goes like this:
  • Assembler (fastest).
  • Compiled Static, unsafe languages C/C++.
  • JITed Static, safe languages (C#, Java).
  • ...
  • A large performance gap goes here.
  • ...
  • JITed Dynamic, safe languages (IronPython)
  • Interpreted dynamic, safe languages and mainstream (Python, Perl, Javascript).
  • In-house custom languages.
As I said, the above is just a rough approximation.
The worst kind of language tends to be the in-house custom language.   These in-house and ad-hoc languages tend to be quick hacks that evolve over the life time of a program.   The authors of those languages are not language designers or experts in language design nor compiler developers, so their languages suffer as a result.   The languages tend to be slow, buggy, poorly documented and packed with quirks.
This is why many developers tend to look for more mature language implementations when possible.
Extending your applications has many benefits.   By using a scripting language, you will get an environment that is suitable for quickly prototyping without having to rebuild your core product for small changes, or polishing an existing application.   
Scripting languages also offer a secure execution sandbox that allows high-level developers to quickly prototype and experiment without having to worry about many low-level details of the core C engine and without having to take care of some of the more mundane details like resource management and memory management, vastly simplifying the development of applications.
By splitting the responsibilities between the engine developer and the scripting developer, it is possible to reduce the complexity in a software project and it allows developers to focus on the bigger picture instead of having to learn all the details of the underlying core engine implementation for your software and the various rules for resource management that you might have.
The Mono Offering Mono offers the same functionality that developers have used to extend their application with a safe environment for scripting language with Just-in-Time compiled code.   
Scripting languages tend to be interpreted, and as such are not as fast as native code.  Mono expands the option of scripting language users to use languages that are suitable to be JIT-compiled into native code.   The performance is typically much better than those of a scripted language and many of the high-level language benefits are still available to the developer.
It also offers a wide variety of programming languages depending on the needs of your software.
Mono offers:
  • A choice of languages for scripting your application, some examples:
    • Static languages: C#, VisualBasic.NET, RemObject's Pascal.
    • Dynamic languages: Boo (http://boo.codehaus.org), IronPython, IronRuby.
    • Functional languages: Nemerle, F#
    • And of course, many more, see Languages for more details.
  • A native code generator to run your software as fast as possible.
  • Easy support for calling your native code
    • PInvoke allows you skeleton/stub-less invocation of C methods.
    • InternalMethod provide access to raw C/C++ methods.
    • C function pointer to scripting language transitions (a function pointer provided by Mono when invoked would trigger a transition to Mono-controlled code for execution of any scripting capability, very useful for callbacks or notifications).
  • Access to a large body of libraries and reusable components.
Scripting an Application Scripting an application usually exposes some of the internals of the low-level code in one way or another.   Usually there are handles or object systems that are surfaced for the scripting developer to consume.   The developer of the binding will typically have to design the system to allow for the scripting language to consume it.
Game Developers Game developers are some of the major users of scripting technologies, they develop the performance sensitive code in C and assembler and they take advantage of graphics-accelerated hardware, physics libraries, physics accelerated hardware and multi-cpu processing to increase the performance of a game.
Performance Higher-level constructs and game play are typically implemented in a scripting language.   The problem that game developers face with scripting languages is that they are usually the major performance bottleneck in a game.   After spending years fine-tuning their C, C++ and assembly language code and taking advantage of every little trick in their GPUs, the game play ends up running very slow because the scripting language is just not as fast as it could be.
Consider SecondLife (http://www.secondlife.com), an online 3D virtual world that is scripted with the LSL programming language.   An ongoing effort at Linden Labs is replacing the LSL scripting engine with the Mono runtime.   They have written an LSL compiler that will generate the ECMA bytecode consumed by the Mono runtime, this allows them to keep all of their existing scripts running without modifications and get the advantages of Mono.
The early results of switching showed that there was a 50 to 150 times performance increase in switching from LSL/interpreted to LSL/Mono.
The Unity3D (http://unity3d.com) game design engine uses Mono to provide scripting capabilities to the applications and games built with it by supporting Boo, C# and UnityScript (a strongly-typed version of Javascript which helps make the code faster).
Language Support By using Mono as a scripting engine, you get to pick the language that better suits your needs.   Mono's extensive language support allows developers to pick the best language or the best languages for their particular problem.
Developers familiar with LUA can use the LUA2IL (http://www.lua.inf.puc-rio.br/luanet/lua2il/) compiler to run their existing code, or apply existing skills to run the same LUA code under the Mono optimizing JIT compiler at increased speed.
In addition, developers get to reuse their experience with C# and the .NET class libraries with their game, companies get access to a larger pool of developers that are experienced with a mainstream language and they can focus on creating the best possible game play instead of spending precious resources and time implementing yet another virtual machine, another set of debugging tools and a new ad-hoc language.
Mono allows code to be written in multiple languages: components can be authored in C# that is a language with strong support for best engineering practices (your core libraries, and reusable components can be authored in it) and yet allow the flexibility of a scripting language like Python or Javascript for code that you must quickly prototype or alter.
C#'s support for yielding execution is also very convenient for writing clear code that must maintain state.
The Boo programming language (http://boo.codehaus.org/) is also a popular choice.   This language is an extensible programming language which allows developers to create new language constructs that can be applied to the particular scenarios that are necessary for your game.
Licensing Mono is an open source technology that can be used freely under the terms of the GNU LGPL license.   Novell alternatively offers commercial licenses of the Mono runtime if you require to use Mono in any of the following situations:
  • On Windows or Mac games, if:
    • Static linking Mono into your application.
    • Preventing Mono or its class libraries from being upgraded (for example, to prevent gamers from cheating).
    • You want to add proprietary extensions that you want to keep.
  • On Consoles where the end user is not allowed to upgrade the Mono runtime and repackage the game:
    • Wii, PS3 or Xbox360
  • Proprietary extensions:
    • If your game requires proprietary extensions that would be incompatible with the LGPL.
Mono Tools for Visual Studio Ultimate Edition (http://www.go-mono.com/store/#Mono_Tools_Ultimate) includes a commercial license to redistribute Mono under non-LGPL terms on Windows, Linux, and Mac OS X PCs for products with volumes under 100,000 and revenues under $2M annually. If your organization intends to redistribute software which embeds or bundles Mono, but is unable to comply with the terms of GNU LGPL v2, the Ultimate Edition may be right for you.
For other licensing options, contact us.
Continued Performance Increase  We are committed to improving Mono's JIT performance and code generation quality.    In the last year plenty of optimizations have been done to the runtime in many areas and applications run as much as twice as fast just by upgrading to a newer version of the Mono runtime.
As Mono matures, and its JIT compiler evolves you can expect bigger performance improvements becoming available for your software.
Using Mono in  your Application Now that you have seen a high-level overview of what scripting with Mono can do, you can take a look at the Embedding Mono page for the actual technical details of how you consume the Mono runtime in your application: how you compile against it, and the APIs that your application can use.

TOP

http://www.mono-project.com/Embedding_Mono

Embedding Mono            Table of Contents1 Source Code

2 How Embedding Works

3 Embedding the Runtime

3.1 Compiling and Linking
3.2 Initializing the Mono runtime

3.2.1 Configuring the Runtime


3.3 Shutting down the runtime
3.4 Exposing C code to the CIL universe
3.5 Windows Considerations



4 Updates for Mono version 2.8+

5 Invoking Methods in the CIL universe

5.1 Invoking a Method

5.1.1 Creating objects
5.1.2 Data types
5.1.3 Unmanaged to Managed Thunks


5.2 Threading issues
5.3 Signal handling


6 API Documentation

7 Common Problems

7.1 Threads
7.2 Missing functionality


8 Samples



                    
        by Miguel de Icaza (miguel@ximian.com), Paolo Molaro (lupus@ximian.com)
This document describes how to embed the Mono runtime in yourapplication, and how to invoke managed methods from C, and how toinvoke C code from managed code.
For a general overview of why you would like to embed Mono in your application see the Scripting With Mono article.
Source Code Source code and samples for Mono embedding can be found in the Mono distribution in the mono/samples/embed directory.
How Embedding Works Typically you would begin with an existing C application:

Embedding links the mono runtime with your application, so your application now has a full virtual execution system running side-by-side with it. This is done by linking `libmono' with your application (we will cover the details about this later). Once linked, the address space of your application would look like this:
[url=http://www.mono-project.com/Imageinked.png][/url]
The Mono embedded API exposes the Mono Runtime to the existing C code. The interface exposed by the Mono runtime lets the developer control various aspects of the runtime and inspect the code that runs on the CIL world inside the Mono runtime.
Once you have the Mono runtime initialized, the most interesting thing to do is to load some CIL/.NET code into it.   The code can be written in any of the Mono supported languages like C#, Java, IronPython or Visual Basic.  This will result in an address space like this:
[url=http://www.mono-project.com/Imageoaded.png][/url]
The C code is typically referred as unmanaged code, while the CIL code generated by a CIL-compiler is referred to as managed code.
But to make the system more interesting than just load some managed code and have it run side-by-side with your code, it is desirable to have the managed code invoke C code, and the C code invoke managed code.
Managed code can invoke unmanaged code in two ways, using P/Invoke or using the low-level Mono embedding API.  
The result looks like this:
[Image:exposing.png]  Now your existing C code can trigger methods in the managed world, and the managed world can react and notify of any interesting changes to the C code:
Missing image
Callback.png
Image:callback.png


The loaded assembly can be as simple as you want, some common things that developers have done:  
  • Load a library of methods that are wired to the user interface of an application: GUI elements, dialog boxes are then handled on the managed world, while core processing remains in C.
  • Load user defined code as assemblies, and trigger invocations of those from the existing C code base.
  • Move some of the development to the managed world, gaining all of the benefits of managed development (exception handling, runtime type checking, just-in-time compilation, rich introspection system, type-safe libraries and more) while keeping your existing investment in C intact.
  • A launcher that launches background threads to perform some work on behalf of the application.
  • Embed a web application or a web service server inside your application.
  • Use Mono to host the user scripting interface, turning Mono and the scripts into a generic plugin interface.
  • Integrate the Mono object system with third-party object systems.
Since the Mono framework is a fairly powerful framework there are almost no limitations on the different kind of applications that you can create with the above setup.
Embedding the Runtime Embedding the runtime consists of various steps:
  • Compiling and linking the Mono runtime
  • Initializing the Mono runtime
  • Optionally expose C code to the C#/CIL universe.
These are discussed in detail next.
Compiling and Linking To embed the runtime, you have to link your code against theMono runtime libraries.  To do this, you want to pass theflags returned by pkg-config to your compiler:
$ pkg-config --cflags --libs mono-2is used to get the flags for the JIT runtime.
Like this:
$ gcc sample.c `pkg-config --cflags --libs mono-2`You can separate the compilation flags from the linking flags, for instance, you can use the following macros in your makefile:
CFLAGS=`pkg-config --cflags mono-2`
LDFLAGS=`pkg-config --libs mono-2`For mono versions before 2.8, use "mono" instead of "mono-2" in the above commands: the ABI version of the libmono library has changed.
On windows you need to generate an import library for mono.dll by getting the following file:
http://github.com/mono/mono/blob/master/msvc/mono.def
and creating mono.lib with the command:
lib /nologo /def:mono.def /out:mono.lib /machine:x86Then you link your application with mono.lib.
Initializing the Mono runtime To initialize the JIT runtime, call mono_jit_init, like this:
        #include <glib/glib.h>
        #include <mono/jit/jit.h>
        #include <mono/metadata/assembly.h>

        MonoDomain *domain;

        domain = mono_jit_init (domain_name);That will return a MonoDomain where your code will beexecuted. domain_name is the name of the main application domain.This call will initialize the default framework version, which could be 2.0 or 4.0, depending on the Mono version used. To specify a framework version, you can use something like:
       domain = mono_jit_init_version ("myapp", ""v2.0.50727);The first thing you usually do is to load your assembly and execute it:
        MonoAssembly *assembly;

        assembly = mono_domain_assembly_open (domain, "file.exe");
        if (!assembly)
                error ();In the above example, the contents of `file.exe' will beloaded into the domain.  This only loads the code, but it willnot execute anything yet.  You can replace `file.exe' withanother transport file, like `file.dll'.
To start executing code, you must invoke a method in theassembly, or if you have provided a static Main method (anentry point), you can use the convenience function:
        retval = mono_jit_exec (domain, assembly, argc - 1, argv + 1);Make sure you always provide a Main() method and execute it with mono_jit_exec()at startup: this sets up some additional information in the application domain, like the main assembly and the base loading path. You will be able to execute other methods even after Main() returns.
If you want to invoke a different method, look at the`Invoking Methods in the CIL universe' section.
Certain features of the runtime like Dll remapping depend on a configuration file, to load the configuration file, just add:
         mono_config_parse (NULL);Which will load the Mono configuration file (typically /etc/mono/config), but if you want to load your own configuration file, pass the filename as the argument to mono_config_parse:
         mono_config_parse ("my_mappings"); Configuring the Runtime When Mono is embedded into an application it needs a way of finding its runtime assemblies and configuration files.  By default it will use the system defined locations that the runtime was built with (typically assemblies in /usr/lib/mono and configuration in /etc/mono).  This will work out of the box for you.
But if you are using a Mono that was relocated from an original distribution, for example if you are distributing your application with Mono, you must inform the Mono runtime where to find its assemblies and configuration files.  To do so, you must call the mono_set_dirs routine:
     mono_set_dirs (myapp_lib, myapp_etc);In Windows this is common since you will install your Mono on a different directory, so for example:
mono_set_dirs("C:\\Mono-2.6.7\\lib","C:\\Mono-2.6.7\\etc"); Shutting down the runtime To shutdown the Mono runtime, you have to clean up all thedomains that were created, use this function:
        mono_jit_cleanup (domain);
Note that for current versions of Mono, the mono runtime can't be reloaded into the same process, so call mono_jit_cleanup() only if you're never going to initialize it again.
Exposing C code to the CIL universe The Mono runtime provides two mechanisms to expose C code tothe CIL universe: internal calls and native C code.   Internalcalls are tightly integrated with the runtime, and provide no supportfor marshalling between runtime types and C types.
For example, passing a C# string will result into a MonoString* in the C function when using an internal call (that is, it will be a pointer to the managed heap object representing the string). A C# string passed to a P/Invoke C function will result instead in, for example, a utf8 char pointer, depending on the marshalling attributes.
The other option is to use the Platform Invoke (P/Invoke) tocall C code from the CIL universe, using the standard P/Invokemechanisms.
To use the P/Invoke system, you have to make your C function public, for example:
void DoSomething ()
{
   /* ... */
}To make the runtime lookup the symbol in the current executable, use the special library name __Internal like this, in your DllImport attribute:
using System.Runtime.InteropServices;

[DllImport ("__Internal", EntryPoint="DoSomething")]
static extern void DoSomething ();The "__Internal" library name will instruct Mono not to look this up in an external library, but to try to satisfy the symbol referenced (DoSomething) in the current executable image.
The P/Invoke framework provides extensive marshalling capabilities (converting strings, converting data types, mapping delegates to function pointers and much more).    This is the simplest mechanism to use.
If you want direct access to managed objects you can register C code with the runtime, and later bind to it from managed code.
To register an internal call, use this call in the C code:
        mono_add_internal_call ("Hello::Sample", sample);
Now, you need to declare this on the C# side:
        using System;
        using System.Runtime.CompilerServices;
       
        class Hello {
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        extern static string Sample ();
        }
Since this routine returns a string, here is the C definition:
        static MonoString*
        Sample ()
        {
                return mono_string_new (mono_domain_get (), "Hello!");
        }
Notice that we have to return a `MonoString', and we use the`mono_string_new' API call to obtain this from a string.
Windows Considerations On Windows, it is necessary for you to flag any methods that you want to expose through P/Invoke to be flagged with __dllexport or __declspec(dllexport).
Updates for Mono version 2.8+ To support advanced GC implementations, implement a few optimizations and to do a much needed cleanup, the API and ABI exposed by the Mono library starting with version 2.8 has changed.Most of the API remains unchanged, but a few tweaks may be needed in the build setup and in the code. As much as possible the changes needed will allow the code to compile with both API versions.
The first thing to change is to use mono-2 instead of mono in the pkg-config invocations. To get the preprocessor flags to use during compilation, for example, you'll use:
pkg-config --cflags mono-2
Please also note that mono may not use GLib anymore internally, so if you use it in your program, make sure you also link to it explicitly.No other change to the build setup should be needed.
Now let's list the changes that may be needed to the source code.
  • The glib.h header file is no longer included in the mono header files, so if you use GLib and relied on mono including the header for you, you'll need to explicitly include the glib.h header now.
  • A few functions in the API return a pointer to allocated memory: this memory must be freed with mono_free() instead of g_free().
FIXME: provide a list or a small script to allow people to easily grep for them in their code.
  • A few internal headers are not installed anymore. You should simply remove the inclusion on those headers. This includes headers in the mono/utils directory (except mono-logger.h and the newly added mono-publib.h), headers in the mono/io-layer directory and mono/metadata/mempool.h.
  • The MonoType struct is no longer fully visible: if you have code that accesses its fields directly, you need to change it to use the accessors that are already provided also in the 1.0 version of the mono API.
For example, if you accessed the byref flag of the type using:
type->byref
you need to change the code to read:
mono_type_is_byref (type)
  • The MonoMethodSignature struct is no longer fully visible: if you have code that accesses its fields directly, you need to change it to use the accessors that are already provided also in the 1.0 version of the mono API.
For example, if you accessed the return type of the signature using:
signature->ret
you need to change the code to read:
mono_signature_get_return_type (signature)
  • The MonoArray and MonoString structures are no longer visible.
If you accessed the fields directly, you need to change the codeto use the macros and functions already part of the API.
  • The MonoAssemblyName struct is no longer fully visible: to access its fields
you need to use the newly-provided accessors. Note also that it can't be allocated on the stack anymore and you'll need to create and destroy it withthe following API:
MooAssemlyName *aname = mono_assembly_name_new ("mscorlib");
mono_assembly_name_free (aname);
  • The MonoMethodHeader object is now transient: you need to free it when you're done to avoid leaking by calling the (already existing and safe to call) function mono_metadata_free_mh ().
  • Array API changes: the integer types that represent arry lengths and array boundaries has changed to uintptr_t and intptr_t. This allows us to transparently provide a mono build that supports 64 bit indices on 64 bit systems. The affected APIs are:
mono_array_new ()
mono_array_new_full ()
mono_array_new_specific ()
mono_array_length ()
  • Profiler API changes.
Mono can now support multiple profilers running at the same time. The profilerinitialization sequence must first install the profiler and only after thatinstall the callbacks and set the event mask.
Also note that objects can move in memory. Use the
void mono_profiler_install_gc_moves    (MonoProfileGCMoveFunc callback);
function to get notifications of the old and new addresses of objects as they are moved.
  • The mono logger API now exposes only the ability to set the trace level and trace mask with the two functions:
void mono_trace_set_mask_string (const char *value);
void mono_trace_set_level_string (const char *value);
  • The following methods and structures (which were really unlikely to be used/useful to anyone outside of the mono internals) are not part of the public API anymore:
mono_remote_class() MonoRemoteClass
ves_icall_System_Environment_GetOSVersionString()
mono_alloc_special_static_data()/mono_get_special_static_data()
Invoking Methods in the CIL universe Calling a method in the CIL universe from C requires a number of steps:
  • Obtaining the MonoMethod handle to the method.
  • The method invocation.
To get a MonoMethod there are several ways.
You can get a MonoClass (the structure representing a type)using:
        MonoImage *
        mono_assembly_get_image  (MonoAssembly *assembly);

        MonoClass *
        mono_class_from_name (MonoImage *image, const char* name_space, const char *name);
and then loop in the returned class method array until you get the one you're looking for. There are examples of such searches as static functions in several C files in metadata/*.c: we need to expose one through the API and removethe duplicates.
The other, simpler, way is to use the functions in debug-helpers.h: there are examples of their use in monograph, mint and the jit as well.  You basically use a string description of the method, like:
        "System.Object:GetHashCode()"
and create a MonoMethodDesc out of it with:
#include <mono/metadata/debug-helpers.h>

MonoMethodDesc* mono_method_desc_new (const char *name, gboolean include_namespace);
You can then use:
MonoMethod*     mono_method_desc_search_in_class (MonoMethodDesc *desc, MonoClass *klass);
MonoMethod*     mono_method_desc_search_in_image (MonoMethodDesc *desc, MonoImage *image);
and
#include <mono/metadata/assembly.h>

MonoImage    *mono_assembly_get_image  (MonoAssembly *assembly);
to search for the method in a class or in an image.  You wouldtypically do this just once at the start of the program andstore the result for reuse somewhere.
Invoking a Method There are two functions to call a managed method:
        MonoObject*
        mono_runtime_invoke         (MonoMethod *method, void *obj, void **params,
                                     MonoObject **exc);
        and
        MonoObject*
        mono_runtime_invoke_array   (MonoMethod *method, void *obj, MonoArray *params,
                                     MonoObject **exc);obj is the 'this' pointer, it should be NULL for staticmethods, a MonoObject* for object instances and a pointer tothe value type for value types.
The params array contains the arguments to the method with the same convention: MonoObject* pointers for object instances and pointers to the value type otherwise. The _invoke_array variant takes a C# object[] as the params argument (MonoArray *params): in this case the value types are boxed inside the  respective reference representation.
From unmanaged code you'll usually use the mono_runtime_invoke() variant.
Note that this function doesn't handle virtual methods for you, it will exec the exact method you pass: we still need to expose a function to lookup the derived class implementation of a virtual method (there are examples of this in the code, though).
You can pass NULL as the exc argument if you don't want to catch exceptions, otherwise, *exc will be set to the exception  thrown, if any.  if an exception is thrown, you can't use the MonoObject* result from the function.
If the method returns a value type, it is boxed in an object.
For example, to invoke the following C# methods:
  class MyClass {
    static void Foo (int value) {
      ...
    }

    int Bar (string name) {
      ...
    }
  }assuming you got the corresponding MonoMethod* in foo_method and bar_method and this_arg is a MonoObject* of type MyClass, you simply execute:
  /* we execute methods that take one argument */
  void *args [1];
  int val = 10;
  /* Note we put the address of the value type in the args array */
  args [0] = &val;

  /* execute Foo (10);
   * it's a static method, so use NULL as the second argument.
   */

  mono_runtime_invoke (foo_method, NULL, args, NULL);

  /* a string is a reference, so we put it directly in the args array */
  args [0] = mono_string_new (domain, "Hello");
  /* execute my_class_instance.Bar ("Hello");
   * See the Creating Objects section to learn how to get this_arg.
   */

  MonoObject *result = mono_runtime_invoke (bar_method, this_arg, args, NULL);
  /* we always get a MonoObject* from mono_runtime_invoke (), so to get
   * the integer value we need to unbox (which returns a pointer to
   * the value stored in the object) and dereference.
   */

  int int_result = *(int*)mono_object_unbox (result); Creating objects Creating an object involves two separate actions: allocating the memoryand invoking the constructor.
For constructors that take no arguments this is very simple:
  /* we usually get the class we need during initialization */
  MonoImage *image = mono_assembly_get_image (assembly);
  MonoClass *my_class = mono_class_from_name (image, "MyNamespace", "MyClass");
  ...
  /* allocate memory for the object */
  MonoObject *my_class_instance = mono_object_new (domain, my_class);
  /* execute the default argument-less constructor */
  mono_runtime_object_init (my_class_instance);For more complex constructors or if you want to have more control of the execution of the constructor, you can use mono_runtime_invoke() as explained in the previous section, after getting the MonoMethod* representing the constructor:
  /* execute my_class_instance = new MyClass ("Mono rocks"); */
  MonoObject *my_class_instance = mono_object_new (domain, my_class);
  void *args [1];
  args [0] = mono_string_new (domain, "Mono rocks");
  /* constructor methods return void, so we ignore the return value,
   * the constructed object is my_class_instance.
   */

  mono_runtime_invoke (ctor_method, my_class_instance, args, NULL); Data types Unlike PInvoke, there is no intermediate layer that translates the managed types into unmanaged typed or the other way around.   With the embedded runtime, when you register an internal call, or when you call a method, you need to use the data types expected by the runtime.
This means that you need to convert your C types into Mono runtime types before you can pass them to Mono, or you must convert those Mono types to C types before you can consume them"
C Type Mono Type   C to Mono Mono to C
strings, char * MonoString * mono_string_new, mono_string_new_len,mono_string_new_wrapper, mono_string-new_utf16
mono_string_to_utf8, mono_string_to_utf16
array of x MonoArray * mono_array_new, mono_array_new_full, mono_array_new_specific
See the embedded API documentation for more details about these.
Unmanaged to Managed Thunks With Mono 2.0 we introduced a new function that can wrap a MonoMethod into a function pointer:
        void* mono_method_get_unmanaged_thunk (MonoMethod *method);You'll be able to store the returned pointer in a function pointer with the proper signature and call that directly fromC:
        typedef gint32 (*GetHashCode) (MonoObject *obj);

        GetHashCode func = mono_method_get_unmanaged_thunk (System_Object_GetHashCode_method);

        gint32 hashvalue = func (myobject);Another approach is calling Marshal.GetFunctionPointerForDelegate () (http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.getfunctionpointerfordelegate.aspx) either from managed code, or using mono_runtime_invoke ().
Pre-2.0 notes:It may not be possible to manage exceptions in that case, though. I need to think more about it.
Threading issues If your application creates threads on its own, and you want them to be able to call code into the CIL universe with Mono, you have toregister the thread with Mono before issuing the call.
To do so, call the mono_thread_attach() function before you executeany managed code from the thread
Signal handling Mono consumes a set of signals during execution that your applications will not be able to consume, here is what these are:
  • SIGPWR, SIGXCPU: these are used internally by the GC and pthreads.
  • SIGFPE: caught so we can turn that into an exception
  • SIGQUIT, SIGKILL to produce ExecutionEngineException.
  • SIGSEGV: to produce NullReferenceExceptions
One signal picked at startup time between SIGRTMIN and SIGRTMAX.  The signal is picked up by finding a signal in that range which is set to SIG_DFL.
Optionally:
  • SIGUSR2: this is used when --trace=disable is passed on the command line and its used to turn on/off the output of trace.
Currently Mono does not provide a mechanism for signal chaining, but one might be available in the future, see Bug #75990 (http://bugzilla.ximian.com/show_bug.cgi?id=75990) for information on the current status of this feature.
API Documentation See here (http://go-mono.com/docs/index.aspx?tlink=root:/embed).
Common Problems  Threads If your applications has threads that will access Mono, access Mono variables, point to Mono objects, be called back by Mono, these threads must be registered with the Mono runtime using the mono_thread_attach.
Missing functionality If the embedding API is missing some functionality, you might be able to work around it by invoking managed code using mono_runtime_invoke (), i.e. for creating delegates you can call Delegate.CreateDelegate () etc.
Samples See the sample programs in mono/samples/embed (http://anonsvn.mono-project.com/viewvc/trunk/mono/samples/embed/) for examples ofembedding the Mono runtime in your application.

TOP

Thread