简体   繁体   中英

Calling a C++ DLL from C# with unions

I am receiving callbacks from a C++ DLL and need to accept a struct looking like this:

typedef struct {
  union {
    SXAnyDevice any_device;
    SXInternalDevice internal;
    SXExternalDevice external;
  }
  int device_type;
} SXDevice;

I have created structs that are referenced in C# and have set an explicit layout but I have a problem with setting the FieldOffset for the device_type field as the referenced structs in the union are not all of the same size.

[StructLayout(LayoutKind.Explicit, CharSet=CharSet.Ansi)]
public struct SXDevice {
    [FieldOffset(0)]
    public SXAnyDevice any_device;
    [FieldOffset(0)]
    public SXInternalDevice internal_device;
    [FieldOffset(0)]
    public SXExternalDevice external_device;
    [FieldOffset(**Not sure how to handle this**)]
    public int device_type;
} 

Any ideas how best to do this?

How to quickly get the offset: use the value returned by offsetof(SXDevice, device_type) in C++.

Explanation for the offset:

An union takes as much space as it's biggest component.

Let maxSize = max(sizeof(SXAnyDevice), sizeof(SXInternalDevice), sizeof(SXExternalDevice))

Now everything depends on how it's configured on the C++ side:

  • If there is no padding ( #pragma pack(1) ), then offset of device_type will be simply equal to maxSize
  • If there's padding, align maxSize to the next pack boundary

From the #pragma pack docs :

Specifies the value, in bytes, to be used for packing. If the compiler option /Zp is not set for the module, the default value for n is 8. Valid values are 1, 2, 4, 8, and 16. The alignment of a member will be on a boundary that is either a multiple of n or a multiple of the size of the member, whichever is smaller.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM