2

私はC++で以下を持っています:

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# ラッパーを宣言してみました。

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 を参照するプログラムを実行するとすぐに、「オフセットにオブジェクト フィールドが含まれているため、アセンブリ 'UnmanagedToManaged、Version=1.0.0.0、Culture=neutral、PublicKeyToken=null' からタイプ 'TestUnion' をロードできませんでした' が表示されます。 0 が正しく整列されていないか、オブジェクト以外のフィールドと重なっています。".

これは単なるテストプログラムです。ユニオンを削除するための別の質問で提案を見ました。ただし、事前に DLL によってどの構造が埋められるかはわかりません。私が間違っていることについて誰かがアドバイスを提供できますか?

4

1 に答える 1

0

デフォルトのマーシャラーがこれを自動的に処理できる方法はありません。構造体のどの部分を使用する必要があるかを知る方法がないため、アンマネージ関数から戻るときに構造体をマーサルする方法を知ることができませんTestUnion。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;
    }
}
于 2012-09-12T16:34:11.673 に答える