2014-05-14 6 views
5

Ich möchte untersuchen, wie iOS-Bibliothek mit der Verarbeitung Zeiger auf Xamarin.iOS binden. Es muss Marshalling.Wie bindet man Xamarin iOS Obj-C-Bibliothek mit Marshalling

ich eine solche Bibliothek für den Test vorbereiten,

MarshalTest.h

typedef struct 
{ 
    float x,y,z; 
} Marshal3D; 


@interface MarshalTest : NSObject 

-(id)initWithMarshal:(Marshal3D *)marshal; 
-(id)initWithMarshals:(Marshal3D *)marshals num:(int)numCoord; 

-(void)addMarshal:(Marshal3D *)marshal; 
-(void)addMarshals:(Marshal3D *)marshals num:(int)numCoord; 

-(int)getMarshals:(Marshal3D **)getMarshals; 

-(int) storedNumber; 
-(float)checkMarshalValue:(int)index xyz:(int)xyz; 

@end 

und bereiten Binding C# Codes wie folgt aus:

StructsAndEnums.cs

using System; 
using System.Runtime.InteropServices; 

namespace MarshalTestNet 
{ 
    [StructLayout(LayoutKind.Sequential)] 
    public struct Marshal3D 
    { 
     public float x; 
     public float y; 
     public float z; 
    }; 
} 

ApiDefinition.cs

using System; 
using System.Drawing; 
using System.Runtime.InteropServices; 

using MonoTouch.ObjCRuntime; 
using MonoTouch.Foundation; 
using MonoTouch.UIKit; 

namespace MarshalTestNet 
{ 
    [BaseType (typeof (NSObject))] 
    public partial interface MarshalTest { 

     [Export ("initWithMarshal:")] 
     IntPtr Constructor ([In, MarshalAs(UnmanagedType.LPStruct)]Marshal3D marshal); 

     [Export ("initWithMarshals:num:")] 
     IntPtr Constructor ([In, MarshalAs(UnmanagedType.LPStruct)]Marshal3D marshals, int numCoord); 

     [Export ("addMarshal:")] 
     void AddMarshal ([In, MarshalAs(UnmanagedType.LPStruct)]Marshal3D marshal); 

     [Export ("addMarshals:num:")] 
     void AddMarshals ([In, MarshalAs(UnmanagedType.LPStruct)]Marshal3D marshals, int numCoord); 

     [Export ("getMarshals:")] 
     int GetMarshals ([Out, MarshalAs(UnmanagedType.LPStruct)]Marshal3D getMarshals); 

     [Export ("storedNumber")]//, Verify ("ObjC method massaged into getter property", "/Users/kokogiko/Desktop/MarshalTest.h", Line = 32)] 
     int StoredNumber { get; } 

     [Export ("checkMarshalValue:xyz:")] 
     float CheckMarshalValue (int index, int xyz); 
    } 
} 

Aber das funktioniert nicht, nur

wird Nachricht ohne Fehler zeigt
var mars3 = new Marshal3D{ 
    x = 1.0f, 
    y = 2.0f, 
    z = 3.0f 
}; 
var mars = new MarshalTest (mars3); 

Aufruf beendet.

Wie binden iOS-Bibliothek mit Marshalling? Es gibt nur sehr weniger Informationen, dies zu tun ...

[Bearbeiten nach Rolf Antwort]

Danke Rolf, ich viele Fälle so leid für die Beantwortung so spät getestet.

1.

[Export ("initWithMarshal:")] 
IntPtr Constructor (ref Marshal3D marshal); 

[Export ("addMarshal:")] 
void AddMarshal (ref Marshal3D marshal); 

sehr gut funktioniert. Vielen Dank!

2.

[Export ("initWithMarshals:num:")] 
IntPtr Constructor (Marshal3D[] marshals, int numCoord); 

[Export ("addMarshals:num:")] 
void AddMarshals (Marshal3D[] marshals, int numCoord); 

nicht funktioniert, mit diesen Fehler in der Kompilierung Stufe zeigt:

obj/Debug/ios/MarshalTestNet/MarshalTest.g.cs(140,31): error CS1502: The best overloaded method match for `MonoTouch.Foundation.NSArray.FromNSObjects(params MonoTouch.Foundation.NSObject[])' has some invalid arguments 
    /Developer/MonoTouch/usr/lib/mono/2.1/monotouch.dll (Location of the symbol related to previous error) 
obj/Debug/ios/MarshalTestNet/MarshalTest.g.cs(140,46): error CS1503: Argument `#1' cannot convert `MarshalTestNet.Marshal3D[]' expression to type `MonoTouch.Foundation.NSObject[]' 

so ändere ich das von mir selbst,

ApiDefinition.cs

[Export ("addMarshals:num:")] 
void AddMarshals (IntPtr marshals, int numCoord); 

Extra.cs

public unsafe void AddMarshals (Marshal3D[] marshals) { 
    var count = marshals.Length; 
    fixed (Marshal3D* ptr = &marshals[0]) 
     AddMarshals ((IntPtr)ptr, count);   
} 

dies gut funktioniert.

Aber kann dieser Ansatz nicht für die Verwendung

-(id)initWithMarshals:(Marshal3D *)marshals num:(int)numCoord; 

weil es Konstruktor ist, erlauben keine Logik hinzufügen, bevor übergeordnete Methode aufrufen.

Gibt es eine Möglichkeit, das zu beheben?
Verwenden Sie "Factory-Muster" ist am besten?

3.

[Export ("getMarshals:")] 
[Internal] 
int GetMarshals (IntPtr getMarshals); 

und

public partial class MarshalTest : NSObject { 
    public unsafe Marshal3D [] GetMarshals() { 
     var count = this.StoredNumber(); 
     var array = new Marshal3D [count]; 

     fixed (Marshal3D* ptr = &array[0]) 
      GetMarshals ((IntPtr) ptr); 

     return array;    
    } 
} 

nicht funktioniert.
beendet ohne Fehler in der RUNNIG-Phase.

Ich denke

Marshal3D* ptr = &array[0] 

ein Zeiger ist, aber

-(int)getMarshals:(Marshal3D **)getMarshals; 

braucht Zeiger-of-Zeiger.
Ist es nicht richtig?

Antwort

6

Xamarin.iOS-Bindungsprojekte unterstützen kein benutzerdefiniertes Marshalling.

Aber ich glaube nicht, dass Sie es brauchen:

[BaseType (typeof (NSObject))] 
public partial interface MarshalTest { 

    [Export ("initWithMarshal:")] 
    IntPtr Constructor (ref Marshal3D marshal); 

    [Export ("initWithMarshals:num:")] 
    IntPtr Constructor (Marshal3D[] marshals, int numCoord); 

    [Export ("addMarshal:")] 
    void AddMarshal (ref Marshal3D marshal); 

    [Export ("addMarshals:num:")] 
    void AddMarshals (Marshal3D[] marshals, int numCoord); 

    [Export ("getMarshals:")] 
    [Internal] 
    int GetMarshals (IntPtr getMarshals); 

    // ... 
} 

jedoch GetMarshals schön zu unterstützen, werden Sie verbindlich einen benutzerdefinierten hinzuzufügen (dies typischerweise in der StructsAndEnums.cs Datei ausgeführt wird):

public partial class MarshalTest : NSObject { 
    public unsafe Marshal3D [] GetMarshals() { 
     var count = // how many are there? there's no API to fetch this in your sample 
     var array = new Marshal3D [count]; 

     fixed (Marshal3D* ptr = &array[0]) 
      GetMarshals ((IntPtr) ptr); 

     return array;    
    } 
} 

[Aktualisiert zweiten Satz von Fragen zu beantworten]

  1. Für den Konstruktor, ich denke, das wird funktionieren:

    ApiDefinition.cs

    [BaseType (typeof (NSObject))] 
    public partial interface MarshalTest { 
        [Export ("initWithMarshals:num:")] 
        [Internal] 
        IntPtr Constructor (IntPtr marshals, int numCoord); 
    } 
    

    Extra.cs

    public partial class MarshalTest : NSObject { 
        public MarshalTest (Marshal3D[] marshals, int numCoord) 
         : this (GetPointer (marshals), numCoord) 
        { 
        } 
    
        static IntPtr GetPointer (Marshal3D[] marshals) 
        { 
         fixed (Marshal3D* ptr = &marshals[0]) 
          return (IntPtr) ptr; 
        } 
    

    }

  2. Du hast Recht Es erwartet einen Zeiger auf ein Array. Versuchen Sie stattdessen:

    ApiDefinition.cs

    [BaseType (typeof (NSObject))] 
    public partial interface MarshalTest { 
        [Export ("getMarshals:")] 
        [Internal] 
        int GetMarshals (ref IntPtr getMarshals); 
    } 
    

    Extra.cs

    public partial class MarshalTest : NSObject { 
        public unsafe Marshal3D [] GetMarshals() { 
         var ptr = IntPtr.Zero; 
         var count = this.StoredNumber(); 
         var array = new Marshal3D [count]; 
    
         GetMarshals (ref ptr); 
    
         unsafe { 
          Marshal3D* ptr3d = (Marshal3D *) ptr; 
          for (int i = 0; i < count; i++) 
           array [i] = *ptr3d++; 
         } 
    
         return array;    
        } 
    } 
    
+0

Rolf, vielen Dank für die Beantwortung! Ich habe ein paar Fragen, also habe ich meine erste Frage bearbeitet. – kochizufan

+0

@kochizufan: Ich habe meine Antwort auch aktualisiert –

+0

Vielen Dank, alle von ihnen funktioniert sehr gut, aber eine Frage. Im 1. Fall von Extra.cs ist der zurückgegebene IntPtr-Wert von GetPointer-Funktion außerhalb des "festen" Blocks. Besteht keine Gefahr von SEGV, wenn GC auftritt? – kochizufan