开发者

Exception System.InvalidCastException when calling a method bound with btouch that returns an object. MonoTouch bug?

I am trying to bind the types of an Objective-C library using btouch. I have managed to compile my API definition file with btouch and have successfully called methods that return no parameters or which return basic parameters like string or integer. However, when I try call methods that return instance objects for other classes defined in the API definition file, I get an exception System.InvalidCastException thrown. So in the example listing that follows, the static OpenConnection method of the UltraliteManager class throws this exception when called from a MonoTouch project.

This is the Objective-C header file:

#import <Foundation/Foundation.h>

@interface UltraliteConnection : NSObject {
@private
    void * ulconnection;
}
- (id) initWithULConnection: (void*) connect;
- (void) dealloc;
- (void) close;
- (void) executeStatement: (NSString*) sql;
@end

@interface UltraliteManager: NSObject {}
+ (void) initialize;
+ (void) fini;
+ (UltraliteConnection*) openConnection: (NSString*)connectionParms;
@end

This is the Objective-C implementation (abridged to show just the relevant implementations):

@implementation UltraliteConnection
- (id) initWithULConnection: (void*) connect
{
    [super init];
    ulconnection = connect;
    [self retain];
    return self;
}
- (void) dealloc 
{
    [super dealloc];
}
- (void) close
{
    ULError error;
    ((ULConnection*) ulconnection)->Close(&error);
    [self release];
}
@end

@implementation UltraliteManager
+ (UltraliteConnection*) openConnection: (NSString*)connectionParms
{
    ULError error;
    ULConnection * connbase;
    UltraliteConnection * connwrap;
    connbase = ULDatabaseManager::OpenConnection([connectionParms UTF8String],
                                                 &error, 
                                                 NULL);
    connwrap = [[UltraliteConne开发者_高级运维ction alloc] initWithULConnection:connbase];
    [connwrap release];
    return connwrap;
}
@end

And this is the API definition file:

using MonoTouch.Foundation;

namespace Ultralite {
    [BaseType (typeof (NSObject))]
    interface UltraliteConnection {
        [Export("close")]
        void Close ();
        [Export("executeStatement:")]
        void ExecuteStatement(string sql);
    }
    [BaseType (typeof (NSObject))]
    interface UltraliteManager {
        [Static, Export ("initialize")]
        string Initialize ();
        [Static, Export ("fini")]
        void Fini ();
        [Static, Export ("openConnection:")]
        UltraliteConnection OpenConnection (string connectionParms);
    }
}

I have found that if I return NULL from my implementation of openConnection (ie. replace the line return connwrap; with return nil;) then the method returns without throwing an exception. So it seems to me that this exception has to do with returning of the UltraliteConnection object to MonoTouch.

Anyone have any idea what is causing this problem and how I can resolve it?


I have managed to work around this issue and it does indeed seem to be a bug in MonoTouch. My workaround was to call btouch with the outdir parameter set and then include the generated C# files in my project. So, instead of doing this:

btouch ultralite.cs enum.cs

I did:

btouch ultralite.cs enum.cs -outdir=.

This generated files in two folders ObjCRuntime and Ultralite (the name of my namespace). I removed the ultralite.dll from the references of my project, and instead copied and included the files from these two directories that btouch generated. With the C# files included instead of the dll as reference, the OpenConnection method that I referred to in my question executed correctly and returned the connection object.

I never made any changes to my Objective-C wrapper library, nor the API definition file, so it definitely seems to be a bug in btouch. Or maybe I was missing some other required argument in my original call to btouch. Maybe someone from MonoTouch could shed some light on this.

But, bottom line, my library is finally imported and working correctly in MonoTouch. :) I hope that this information is helpful to anyone else who encounters this problem.


I think the problem is that the native UltraliteConnection object is being initialized with a specific method - initWithULConnection:.

Since this is the case, you have to implement a constructor in your API definition of the UltraliteConnection object:

[Export ("initWithULConnection:")]  
IntPtr Constructor (ULConnection connbase);

And of course, you will also need to bind the ULConnection object for this to work.

It doesn't matter that you have the evaluation version of MonoTouch, it is the same as the commercial, you just can't deploy to devices and the App Store with it.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜