2012-09-12 42 views
2

我有C++中的以下內容:一旦非託管工會與字符數組

public class WrapperClass 
    { 
     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
     public struct TestA 
     { 
      public int i; 
      [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 512)] 
      public string text; 
     } 

     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
     public struct TestB 
     { 
      public double n; 
      [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 512)] 
      public string text; 
     } 
     [StructLayout(LayoutKind.Explicit)] 
     public struct TestUnion 
     { 
      [FieldOffset(0)] 
      public TestA a; 

      [FieldOffset(0)] 
      public TestB b; 

     } 

     [DllImport("UnmanagedDLL.Dll")] 
     public static extern int fnUnmanagedDLL(int which,ref TestUnion obj); 
    } 

我運行一個程序,它引用WrapperClass.TestUnion:

struct TestA { 
    int i; 
    char text[512]; 
}; 

struct TestB { 
    double n; 
    char text[512]; 
}; 

union TestUnion { 
    struct TestA a; 
    struct TestB b; 
}; 

int fnUnmanagedDLL(int which,TestUnion *); 

我試圖聲明一個C#包裝這樣的,我得到「無法從程序集'UnmanagedToManaged,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null'加載類型'TestUnion',因爲它包含偏移量爲0的對象字段,該對象字段被非對象錯誤地對齊或重疊領域。」。

這只是一個測試程序。在另一個問題中,我確實看到了關於刪除這個選項的建議。但是,我不知道哪個結構會被DLL預先填充。任何人都可以提供關於我在做什麼錯誤的建議嗎?

回答

0

默認的編組器不能自動處理這個問題。當從非託管函數返回時它不知道如何marhsal結構,因爲它無法知道它應該使用哪個部分。您必須通過更改您的p/Invoke定義來手動執行封送處理以獲取IntPtr,分配緩衝區,然後手動封送到正確的類型。

在下面的例子中我假設的fnUnmanagedDLL返回值是如何確定它在被填充的結構類型。

public class WrapperClass 
{ 
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
    public struct TestA 
    { 
     public int i; 
     [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 512)] 
     public string text; 
    } 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
    public struct TestB 
    { 
     public double n; 
     [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 512)] 
     public string text; 
    } 

    public struct TestUnion // Removed marshal attributes since they cause exceptions 
    { 
     public TestA a; 
     public TestB b; 
    } 

    [DllImport("UnmanagedDLL.Dll")] 
    private static extern int fnUnmanagedDLL(int which, IntPtr obj); 

    public static int UnmanagedDLL(int which, ref TestUnion testUnion) { 
     IntPtr buffer = Marshal.AllocHGlobal(
       Math.Max(Marshal.SizeOf(typeof(TestA)), 
         Marshal.SizeOf(typeof(TestB))); 

     int returnType = fnUnmanagedDLL(which, buffer); 
     switch (returnType) { 
      case 1: // What ever fnUnmanagedDLL returns for TestA 
       testUnion.a = (TestA)Marshal.PtrToStructure(buffer, typeof(TestA)); 
       break; 
      case 2: // What ever fnUnmanagedDLL returns for TestB 
       testUnion.a = (TestB)Marshal.PtrToStructure(buffer, typeof(TestB)); 
       break; 
     } 

     Marhsal.FreeHGlobal(buffer); // Need to manually free the allocated buffer 

     return returnType; 
    } 
} 
+0

謝謝你提供的信息。對於其他讀者來說,有幾個錯別字: –

+0

緩衝區大小隻有四個字節。那麼,有沒有辦法來解釋字符串?另外,如果一個結構有雙重結構,我預計它會更大。 –