Converting custom native MacOS X library to dll using MonoMac

▼魔方 西西 提交于 2019-12-24 15:13:06

问题


I am trying to port a Windows Forms application to MacOS X, using a native interface (.xibs). This app needs to access a hardware device that has MacOS X drivers but I wanted to keep the C# logic already written for the Windows version so it would be easier to update the application in the future. I've created a small Xcode project to test how to access this device and I got it to work, then I rolled it into a .framework and tried to use this in a MonoMac Project. This proved a bit more difficult.

I've mainly followed the following tutorial to figure out which steps to take when, I also copied the example code to be sure I don't run into all kinds of dependency problems because the .framework I've created is a bit more complicated and followed all steps to create a i386 framework (coincidentally I need to compile my driver this way too because it's quite old...) called Simple:

http://brendanzagaeski.appspot.com/xamarin/0002.html

It's a very simple class that looks like this:

@implementation Simple
- (NSString *)run:(BOOL *)successful
{
    *successful = YES;
    return @"OK";
}
@end

I've followed all steps without any problem up til the step detailing how to use sharpie, because this has changed to a command-line only tool with different parameters. I ended up generating the .cs files using the following command instead:

sharpie bind -sdk macosx10.10 -framework Simple.framework -classic -v -c -arch i386

ApiDefinitions.cs looks like this:

using MonoMac.Foundation;

//[Verify (ConstantsInterfaceAssociation)]
partial interface Constants
{
    // extern double SimpleVersionNumber;
    [Field ("SimpleVersionNumber")]
    double SimpleVersionNumber { get; }

    // extern const unsigned char [] SimpleVersionString;
    [Field ("SimpleVersionString")]
    byte[] SimpleVersionString { get; }
}

// @interface Simple : NSObject
[BaseType (typeof(NSObject))]
interface Simple
{
    // -(NSString *)run:(BOOL *)successful;
    [Export ("run:")]
    unsafe string Run (bool* successful);
}

The -classic switch gave me the correct using (MonoMac.Foundation) immediately so I trusted that more, but I've tried also without. The output except for using was identical otherwise.

I've commented out the Verify part since this doesn't compile and is meant as a warning to people using sharpie that something might need to be verified. I've also changed bool* successful to ref bool successful according to the tutorial.

Then I needed bmac. This tool only exists in Xamarin.Mac and if you want to use it on MacMono you first need to compile MacMono manually and use the generated bmac.exe instead. The tutorial used the following command:

/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/usr/bin/bmac -oSimple.dll --tmpdir=/tmp -baselib=/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/usr/lib/mono/XamMac.dll -r=System.Drawing SimpleBindingDefinition.cs

I've changed this to the following command:

mono /Users/Name/Code/monomac/monomac/src/bmac.exe -o Simple.dll --tmpdir=/tmp -baselib=/Users/Name/Code/monomac/monomac/src/MonoMac.dll -r=System.Drawing ApiDefinitions.cs

This generated the following error:

   in Method: System.String Run(Boolean*)
error BI0000: Unexpected error - Please file a bug report at http://bugzilla.xamarin.com
// and more

Fair enough, the tutorial already warned about that boolean ref so I changed it to:

unsafe string Run (ref bool successful);

Now I was left with exactly the same error bar the part about the boolean:

error BI0000: Unexpected error - Please file a bug report at http://bugzilla.xamarin.com
System.NullReferenceException: Object reference not set to an instance of an object
  at Generator.Generate (System.Type type) [0x00000] in <filename unknown>:0 
  at Generator.Go () [0x00000] in <filename unknown>:0 
  at BindingTouch.Main2 (System.String[] args) [0x00000] in <filename unknown>:0 
  at BindingTouch.Main (System.String[] args) [0x00000] in <filename unknown>:0 

So it's sure that it tries to process the method run: and stumbles somewhere, but I am not sure where the actual problem starts. Is the sharpie conversion wrong already or is it the way I changed ApiDefinitions or invoke bmac.exe?


Also tried to create a new framework version without bool ref parameter and removed those two version methods. That didn't change anything.


I am trying to figure out if perhaps it's a compile error when it's compiled in place. Tested: This framework works without a hitch in a regular Xcode project


回答1:


I started to doubt bmac.exe more and more and I finally installed a trial version of Xamarin.Mac. This can be obtained through here: http://forums.xamarin.com/discussion/31680/welcome-to-the-xamarin-mac-forums-and-faq#latest but that might change in the future. This also contained a native version of bmac (without the .exe extension) and this was already doing more the first time I tried. With a little bit of adjustment I got to this call and that generated a .dll:

/Library/Frameworks/Xamarin.Mac.framework/Versions/1.10.0.18/bin/bmac -o Simple.dll --tmpdir=. \ 
-baselib=/Library/Frameworks/Xamarin.Mac.framework/Versions/1.10.0.18/lib/mono/XamMac.dll  \ 
-r=System.Drawing.dll ApiDefinitions.cs -v -unsafe -target:library

This was the .cs file I ended up using:

using System;
using System.Drawing;
using MonoMac.Foundation;

namespace OPN200x
{
    // @interface SimpleClass : NSObject
    [BaseType (typeof(NSObject))]
    interface SimpleClass
    {
        // -(NSString *)run;
        [Export ("run")]
        string Run { get; }
    }
}

When I run the application and create an instance of the class I encounter the error:

Could not create an native instance of the type 'OPN200x.SimpleClass': the native class hasn't been loaded.
It is possible to ignore this condition by setting MonoMac.ObjCRuntime.Class.ThrowOnInitFailure to false.

I am not sure what it's related to but I think the way bmac worked is fine.




回答2:


bmac builds good DLL now. Just missing loading framework in the MonoMac application before init any instance of this library.

if (Dlfcn.dlopen("PathToFrameworksFolder/Simple.framework/Simple", 0) == IntPtr.Zero)
{
Console.Error.WriteLine("Unable to load the dynamic library.");
}

Just go back to: http://brendanzagaeski.appspot.com/xamarin/0002.html and see the bottom of this blog, code of class MainClass



来源:https://stackoverflow.com/questions/29736792/converting-custom-native-macos-x-library-to-dll-using-monomac

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!