Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mixing C# with Objective-C

I would like to use larger body of C# code as a library for Objective-C (Cocoa) application.

I discovered MonoMac project which wraps Cocoa code, but I would rather have standard Cocoa application written in Objective-C, which can call wrapped C# code (other way around).

On Windows I am used to make C++/CLI project which wraps .NET code and exports plain old C interface for C/C++ based apps.

Is there some simple way to achieve this?

like image 678
Filip Kunc Avatar asked Apr 17 '11 09:04

Filip Kunc


People also ask

Can I mix C++ and C?

If the C++ compiler provides its own versions of the C headers, the versions of those headers used by the C compiler must be compatible. Oracle Developer Studio C and C++ compilers use compatible headers, and use the same C runtime library. They are fully compatible.

What is extern C used for?

extern "C" specifies that the function is defined elsewhere and uses the C-language calling convention. The extern "C" modifier may also be applied to multiple function declarations in a block. In a template declaration, extern specifies that the template has already been instantiated elsewhere.

Is C or C++ faster?

Performance-based on Nature Of Language C++ language is an object-oriented programming language, and it supports some important features like Polymorphism, Abstract Data Types, Encapsulation, etc. Since it supports object-orientation, speed is faster compared to the C language.


2 Answers

There is, obviously, no such language as C++/CLI on Mac OS. On Windows, C++/CLI actually compiles as managed code ran by the CLR, that runs native code; since on Mac OS Mono isn't integrated to the system, it's rather the other way around. Your app is native, and it can host managed code.

Mono exposes functions to host a CLR virtual machine inside a process. Since CLR classes aren't directly exposed to your C code, you'll be able to call methods of objects through reflection-like calls.

There is documentation on how to embed Mono into an application on the official site. Since you're not interested in running .NET programs directly, you should rather read the "Invoking Methods in the CIL Universe" section. On Mac OS, you'll want to link against the Mono framework from your /Library/Frameworks folder, instead of using pkg-config.

This really shouldn't replace an actual reading of the above document, but the following can be seen as a guide as to what to expect:

#include <glib/glib.h> #include <mono/jit/jit.h> #include <mono-metadata/assembly.h> #include <mono/metadata/debug-helpers.h>  // create an app domain // http://en.wikipedia.org/wiki/Application_Domain MonoDomain* domain = mono_jit_init("Domain");  // mandatory Cocoa call to show that Mono and ObjC work together NSBundle* mainBundle = [NSBundle mainBundle]; NSString* dll = [mainBundle pathForResource:@"your-dll" ofType:@"dll"];  // load the referenced assembly in our domain MonoAssembly* assembly = mono_domain_assembly_open(domain, [dll UTF8String]); MonoImage* image = mono_assembly_get_image(assembly);  // find the class we want to wrap and create an uninitialized instance MonoClass* classHandle = mono_class_from_name(image, "Name.Space", "YourClass"); MonoObject* object = mono_object_new(domain, classHandle);  // this calls the default, argument-less ctor // for more complex constructors, you need to find the method handle and call it // (helpful hint: constructors are internally called ".ctor", so the description // string will look like "Name.Space.Class:.ctor()") mono_runtime_object_init(object);  // get a method handle to whatever you like const char* descAsString = "Name.Space.YourClass:YourMethod()"; MonoMethodDesc* description = mono_method_desc_new(descAsString); MonoMethod* method = mono_method_desc_search_in_class(description, classHandle);  // call it void* args[0]; mono_runtime_invoke(method, object, args, NULL);  // when you're done, shutdown the runtime by destroying the app domain mono_jit_cleanup(domain); 

If you don't find this very appealing, you may want to go the other way around, as you mentioned, and look into MonoMac, which provides .NET bindings to a large portion of the APIs you may want to use in a Mac application (Cocoa, CoreImage, CoreAnimation, etc) and means to create your own bindings.

like image 132
zneak Avatar answered Oct 03 '22 02:10

zneak


If you're doing this on Mac, then yes, it's possible. On iOS not so much.

On the Mac, if you can create a CLI app in MonoMac, then you can call your CLI app from within your Objective-C app using NSTask. NSTask allows you to easily launch a commandline tool and then capture it's output and interact with it. To do this, you'd do something like:

NSArray *args = [NSArray arrayWithObjects:@"-arg1", @"-arg2", nil]; NSTask *foo = [[NSTask alloc] init]; [foo setLaunchPath:@"/usr/bin/foo"]; [foo setArguments:args];  NSPipe *pipe = [NSPipe pipe]; [foo setStandardOutput:pipe];  NSFileHandle *output = [pipe fileHandleForReading];  [foo launch];  NSData *data = [output readDataToEndOfFile];  NSString *outputStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];  NSLog(@"Got stuff: %@", outputStr); 

Typically, the way you want to do this, is you include the CLI app inside your app bundle. You can then get the path to the CLI app using NSBundles -pathForResource:ofType: method.

iOS doesn't include the NSTask API, so this isn't possible there. I've heard of some folks using MonoTouch to make iOS apps using C#, but as you suggested, I think you're best off sticking with Objective-C for the bulk of your app if possible. Using a CLI app like you describe is definitely an option on the Mac and can be particularly useful when you have a body of code that's already written and tested and works that you just want to "Wrap" with a Cocoa GUI.

So, NSTask is one way to do this using an external CLI executable wrapped in your app bundle. On the other hand, you might be wondering, can you link your C# code directly into Objective-C?

Well, Objective-C is a superset of C, and as such, it has all the capabilities of C. Additionally, if you use Objective-C++ it has all the capabilities of C++ as well. So, IF you can get MonoMac to generate either a C or C++ static library, then yes, you could even just link your static library with your Objective-C cocoa code, and it'll just work. I can't tell you how to make the library from MonoMac, but linking it in is just a matter of adding it to your linked libraries in your build settings in Xcode.

EDIT: I'm not familiar with C++/CLI as a language, and I misinterpreted the meaning of C++/CLI to mean "C++ Command Line Interface app". That said... the techniques I described still apply as possible methods to do what you want to do, but it is NOT using the C++/CLI interface like you can on Windows.

like image 33
Jiva DeVoe Avatar answered Oct 03 '22 01:10

Jiva DeVoe