6
$\begingroup$

I'd like to access Cocoa-API's (Foundation, AppKit) from Mathematica and have researched the following ways:

  1. CocoaLink: A deprecated Package by Rob Schlofield from 2009, which is still available on GitHub but will not compile out of the box due to the introduced changes in the ObjC-Runtime made at that time and around 2010. I got it to work, but not for all Types. I contacted Rob if he will update CocoaLink but he told me that the effort would not justify the usefulness ... unfortunately.

  2. MonoObjC: A Mono/.NET package which can be installed and used after Mono has been installed. Mono allows one to use .NETLink and invoke almost all .NET functions of the 4.0 Framework.

I have tried:

Needs["NETLink`"];

monobjc = LoadNETAssembly["Monobjc"];
foundation = LoadNETAssembly["Monobjc.Foundation"];
appkit = LoadNETAssembly["Monobjc.AppKit"];

Then I tried to load and instantiate a NSString but it failed with Messages telling me that the Bridge to ObjC is not available.

nsstring = LoadNETType["Monobjc.Foundation.NSString"];
sstr = NETNew[nsstring]

NET::netexcptn: A .NET exception occurred: System.TypeInitializationException: An exception was thrown by the type initializer for Monobjc.Foundation.NSString ---> System.TypeInitializationException: An exception was thrown by the type initializer for Monobjc.ObjectiveCRuntime ---> System.EntryPointNotFoundException: monobjc_install_bridge .....

I am not sure if there is more to be done to initialize .NETLink when working with other external mono packages.

$\endgroup$

1 Answer 1

5
$\begingroup$

First, I like to apologize for answering my own question because I overlooked some essential initial steps when working with MonObjC.

Preconditions

In order to access the Cocoa-APIs from Mathematica via .NETLink there need to be installed 2 separate packages:

Both installers create symbolic links/commands which can be accessed from the terminal.

  • mono for running .NET programs and others for several development tasks
  • monobjc for running .NET programs which call Cocoa API's on the Mac via a "bridge"

It turns out that the monobjc command needs to be passed into the MonoPathoption of ReinstallNET, after .NETLink has been loaded.

Example

To see if "something" can be called with monobjc from Mathematica I translated (or better: adapted) the Console Application from the tutorial section:

(* Load NETLink and make monobjc your link object *)
Needs["NETLink`"];
ReinstallNET["MonoPath" -> "monobjc"];

(* Mandatory load commands and initialization of the ObjC Runtime*)
LoadNETAssembly["Monobjc"];
LoadNETAssembly["Monobjc.Foundation"];
LoadNETAssembly["Monobjc.AppKit"];
LoadNETType["Monobjc.ObjectiveCRuntime"];

ObjectiveCRuntime`LoadFramework["Foundation"];
ObjectiveCRuntime`LoadFramework["AppKit"];
ObjectiveCRuntime`Initialize[];

(* Do what you like with Foundation and AppKit *)
LoadNETType["Monobjc.Foundation.FoundationFramework"];
LoadNETType["Monobjc.AppKit.NSScreen"];
LoadNETType["Monobjc.Foundation.NSDictionary"];

username = FoundationFramework`NSFullUserName[]@ToString[]
home = FoundationFramework`NSHomeDirectory[]@ToString[]
screen  = NSScreen`MainScreen@Frame@ToString[]
path = NETNew["Monobjc.Foundation.NSString",
    "/System/Library/Frameworks/AppKit.framework/Resources/version.plist"];
dict = NSDictionary`DictionaryWithContentsOfFile@path;
version = dict@Description@ToString[]

The results on my MacBook

"Xacobeo"
"/Users/xacobeo2002"
"NSRect(NSPoint(0, 0) - NSSize(1280, 800))"
"{
    BuildVersion = 1;
    CFBundleShortVersionString = \"6.9\";
    CFBundleVersion = \"1265.21\";
    ProjectName = AppKit;
    SourceVersion = 1265021000000000;
}"

Final remark

Although the usage of Cocoa functions from Mathematica might be a bit verbose (there is no CocoaToExpression for automatic conversion of NSString, NSNumber, etc. to Mathematica types) it might be useful for somebody to occasionally call native APIs on the Mac. I always felt that on the Windows-Side you have things like CreateCOMObject in .NETLink which have no counterpart on the Mac and so there is at least a (compromised) workaround.

$\endgroup$
1
  • 1
    $\begingroup$ This is way too complicated than it should be. $\endgroup$ Feb 5, 2015 at 18:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.