2011-01-30 60 views
4

我有非託管代碼:編組BYVAL C-結構,在C#中返回值

... 
typedef struct foo 
{ 
int a; 
bool b 
int c; 
} FOO,*LPFOO; 
.... 
__declspec(dllexport) FOO __stdcall GetFoo() 
{ 
    FOO f; 
    <some work> 
    return f; 
} 
.... 

我已經宣佈C#原型的getFoo功能:

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
    private struct Foo 
    { 
     public int a; 
     public bool b 
     public int c; 
    }; 

    [DllImport("foo.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)] 
    [return:MarshalAs(UnmanagedType.Struct)]   
    private static extern Foo GetFoo(); 

但是,當我從C#代碼中調用的getFoo我一直有MarshalDirectiveException-方法的類型簽名不兼容PInvoke。我應該如何聲明C#原型?

+0

似乎非託管`GetFoo`功能不同時,其管理的定義需要採取任何參數一個整數參數。也許這是一個錯字?另外你如何打算釋放`GetFoo`函數分配的非託管內存? – 2011-01-30 20:09:22

+0

對不起,我誤以爲是我的帖子。 offcource它沒有任何參數。非託管GetFoo不分配任何內存對象 – 2011-01-30 20:11:43

回答

8

是的,返回結構的函數往往很難與之互操作。這樣的結構必須是blittable所以pinvoke編組可以傳遞一個指向函數的指針,爲它寫入返回值做好準備。 「blittable」意味着託管代碼中的結構佈局需要與結構的非託管佈局相同。如果不是,那麼需要製作一個副本,pinvoke編組人員不希望在具體的返回值情況下製作該副本。

bool類型是互操作問題,不同的運行時間由不同的選擇。它往往是C中的4個字節(與Windows BOOL類型相比,也是pinvoke的默認值),COM interop(又名VARIANT_BOOL)中的2個字節,C++中的1個字節,CLR中的1個字節。由於目標運行時間未知,因此CLR無法猜測哪個選項是正確的。 BOOL是默認值,4個字節。

即使使用[MarshalAs(UnmanagedType.U1)]迫使精確匹配並不能使它blittable。這很奇怪,我認爲這是一個CLR錯誤。一個很好的解決方法是用byte替換它,你可以使用一個屬性將它換回到布爾值。要注意的是有很多在發佈片段的錯誤,我做了這個版本的工作:

using System; 
using System.Runtime.InteropServices; 

class Program { 
    static void Main(string[] args) { 
     Foo value = GetFoo(); 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    private struct Foo { 
     public int a; 
     private byte _b; 
     public bool b { 
      get { return _b != 0; } 
     } 
     public int c; 
    }; 

    [DllImport(@"c:\projects\consoleapplication3\debug\cpptemp10.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "[email protected]")] 
    private static extern Foo GetFoo(/*int CoreIndex*/); 
} 

typedef struct foo 
{ 
    int a; 
    bool b; 
    int c; 
} FOO,*LPFOO; 

extern "C" __declspec(dllexport) 
FOO __stdcall GetFoo() 
{ 
    FOO f; 
    f.a = 42; 
    f.b = true; 
    f.c = 101; 
    return f; 
}