Unions in C# - incorrectly aligned or overlapped with a non-object field

后端 未结 2 689
旧巷少年郎
旧巷少年郎 2021-01-15 08:56

I am marshaling via PInvoke to a native C dll which expects the following call.

private static extern int externalMethod(IntPtr Data, [MarshalAs(UnmanagedTyp         


        
相关标签:
2条回答
  • 2021-01-15 09:54

    It is difficult to answer this question without knowing what you are trying to achieve. An explicitly-layouted struct is a very bad choice for any normal use-case; this only makes sense if you are using the data in native calls (pinvoke), and in those cases you definitely don’t want to use the managed class string. The [MarshalAs] attribute only takes effect during the call invocations, not constantly every time the field is read from or written to by your managed code. It doesn’t allow you to overlap a string pointer with an int because doing so would allow you to set the pointer to a meaningless value and then accessing the string would crash the CLR. The same is true for arrays, so you can’t use char[] either.

    If you are the author of the native code that you need to call, then I strongly recommend to write four separate methods instead of a single one that accepts four completely different data structures.

    If you cannot change the native code, then you could always declare your four structs A, B, C and D the way you do now and just use them directly, without the union. Just declare four different pinvoke declarations for the same native function (use the EntryPoint property on the [DllImport] attribute).

    0 讨论(0)
  • 2021-01-15 09:58

    Just use the A/B/C/D structs directly and skip the union. In your extern calls, simply substitute the correct struct in the method declaration.

    extern void UnionMethodExpectingA( A a );
    

    If the unmanaged methods actually accept a union and behave differently based on the type passed, then you can declare different extern methods that all end up calling the same unmanaged entry point.

    [DllImport( "unmanaged.dll", EntryPoint="ScaryMethod" )]
    extern void ScaryMethodExpectingA( A a );
    
    [DllImport( "unmanaged.dll", EntryPoint="ScaryMethod" )]
    extern void ScaryMethodExpectingB( B b );
    

    Updated for "length" parameter. The logic still applies. Just create a "wrapper" method and do the same thing.

    void CallScaryMethodExpectingA( A a )
    {
      ScaryMethodExpectingA( a, Marshal.SizeOf( a ) );
    } 
    
    0 讨论(0)
提交回复
热议问题