2010-02-25 14 views
7

Mam niezarządzanego dll, która eksportuje funkcję folowing:Powracający wskaźniki z niekontrolowana do kodu zarządzanego

SomeData* test(); 

załóżmy SomeData jak:

typedef struct _Data Data; 
struct _Data{ 
    int a; 
    int b; 
} 

Teraz chcę wywołać tę funkcję z C# kod. Zacznę określić C# struture potrzebne do niestandardowego Organizowanie tak:

[StructLayout(LayoutKind.Sequential)] 
public class SomeData 
{ 
    public Int32 a; 
    public Int32 b; 
} 

A teraz oświadczam, zarządzaną funkcję:

[DllImport("DynamicLibrary.dll", CharSet=CharSet.Auto)] 
[return: MarshalAs(UnmanagedType.LPStruct)] 
public static extern SomeData test(); 

A w funkcji main mam:

IntPtr ptr = test(); 

Robiąc to, otrzymuję wyjątek MarchalDirectiveException: "Nie mogę" zwrócić wartości zwracanej ": Niepoprawna kombinacja typu zarządzanego/niezarządzanego (Int/UInt musi być sparowana z SysInt lub SysUInt)."

Nie przydzieliłem pamięci dla SomeData w C#, ponieważ spodziewam się, że pamięć jest przydzielona w funkcji C i użyłbym Marshal.Copy, aby przekazać ją do zarządzanej pamięci.

Wszelkie pomysły? Dzięki

------------------------ EDYCJA PO JaredPar ODPOWIEDŹ ----------------- ---

W rzeczywistości popełniłem błąd podczas kopiowania kodu na moje pytanie. Prawdziwy udało podpis używałem było:

[DllImport ("DynamicLibrary.dll", charset = CharSet.Auto)]
[RETURN: MarshalAs (UnmanagedType.LPStruct)]
public static extern IntPtr Test();

Odpowiedź JaredPar jest nadal aktualna. Aby uzyskać właściwe zachowanie, mam 2 opcje:

1) Użyj "public static extern IntPtr test();" (bez atrybutu MarshalAs) podpis, a następnie uzyska dostęp do zwróconego wskaźnika, tak jak zasugerował JaredPar.

2) Użyj "public static extern SomeData test();" (z atrybutem MarshalAs), a następnie po prostu użyj SomeData sd = test();

Odpowiedz

10

Podczas deklarowania funkcji zarządzanej należy dopasować typy wskaźników do wartości odniesienia lub wartości IntPtr. W tym przypadku modyfikator LPStruct nie pomoże. Najprostszym rozwiązaniem jest przekonwertowanie wartości zwracanej testu na wartość IntPtr zamiast na SomeData, ponieważ metoda natywna zwraca wartość wskaźnika. Następnie można zapisać następujące opakowanie:

[DllImport("DynamicLibrary.dll", CharSet=CharSet.Auto)] 
public static extern IntPtr test(); 

public static SomeData testWrapper() { 
    var ptr = test(); 
    try { 
    return (SomeData)Marshal.PtrToStructure(ptr, typeof(SomeData)); 
    } finally { 
    // Free the pointer here if it's allocated memory 
    } 
} 
+0

Jak widać w mojej edycji, popełniłem błąd, gdy napisałem pytanie. Twoja odpowiedź była pomocna i działa, ale wolę skorzystać z wyboru 2) z mojej sekcji edycji. Dzięki –

Powiązane problemy