从C#到C++传递结构数组

35g0bw71  于 2023-05-22  发布在  C#
关注(0)|答案(1)|浏览(199)

我正在尝试创建C#代码,该代码调用具有C接口的DLL中的函数。我是一名C和C++Maven,但我对C#的了解非常有限。我已经设法将DLL加载到C#程序中,并调用其接口使用简单数据类型(如int甚至字符串)的函数。但这一个超出了我的能力,我希望得到一些有用的提示。
DLL声明此入口点:

BOOL WINAPI GetUsers(ALLUSERINFO* pInfo, DWORD size, DWORD* count);

其中pInfo指向一个包含size元素的结构体的C数组,GetUsers函数用数据填充该数组。count接收实际填充的数组元素的数量。pInfocount都是只输出的。
ALLUSERINFO定义为

struct ALLUSERINFO : public USER_INFO2, public PRINCIPAL_INFO
{
    WCHAR Name[10];
    WCHAR Role[256];
};

它的基类是

struct USER_INFO2
{
    WCHAR Name[80];
    WCHAR Password[40];
};
struct PRINCIPAL_INFO
{
    int PrincipalStatus;
    WCHAR UniqueID[39];
};

WCHARwchar_t的typedef。
我假设我必须将基类转换为ALLUSERINFO的嵌入成员,但我完全不知道如何在C#中创建一个包含固定大小C字符串的结构体数组,然后通过指向其第一个元素的指针传递该数组。
我找到了StructLayoutMarshalAs属性,但从我阅读的文档中,我甚至不确定它们是否适合我的情况,更不用说当涉及到结构体的结构体数组时,它们是如何工作的,就像在这种情况下一样。
谢谢大家!

axr492tv

axr492tv1#

您的定义如下:

  • C#不支持结构体继承,你需要把它们作为字段或属性。
  • 使用UnmanagedType.ByValTStrSizeConst作为内联WCHAR数组。确保在结构上设置CharSet = CharSet.Unicode
[DllImport("yourdll.dll")]
static extern bool GetUsers(
  [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] ALLUSERINFO[] pInfo,
  int size,
  [Out]out int count);

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct ALLUSERINFO
{
    public USER_INFO2 UserInfo;
    public PRINCIPAL_INFO PrincipalInfo;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
    public string Name;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
    public string Role;
};

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct USER_INFO2
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
    public string Name;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
    public string Password;
};

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct PRINCIPAL_INFO
{
    public int PrincipalStatus;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 39)]
    public string UniqueID;
};

然后你简单地这样调用它

var buffer = new ALLUSERINFO[100];
if(!GetUsers(buffer, buffer.Length, out var count))
    throw new Win32Exception(Marshal.GetLastWin32Error());

相关问题