获取从本机 dll 到 C# 应用程序的结构数组

发布于 2024-08-23 21:17:35 字数 939 浏览 5 评论 0原文

我有一个 C# .NET 2.0 CF 项目,需要在本机 C++ DLL 中调用方法。此本机方法返回 TableEntry 类型的数组。当调用本机方法时,我不知道数组有多大。

如何将表从本机 DLL 获取到 C# 项目?下面是我现在所拥有的。

// in C# .NET 2.0 CF project
[StructLayout(LayoutKind.Sequential)]
public struct TableEntry
{
    [MarshalAs(UnmanagedType.LPWStr)] public string description;
    public int item;
    public int another_item;
    public IntPtr some_data;
}

[DllImport("MyDll.dll", 
    CallingConvention = CallingConvention.Winapi, 
    CharSet = CharSet.Auto)]
public static extern bool GetTable(ref TableEntry[] table);

SomeFunction()
{
    TableEntry[] table = null;
    bool success = GetTable( ref table );
    // at this point, the table is empty
}


// In Native C++ DLL
std::vector< TABLE_ENTRY > global_dll_table;
extern "C" __declspec(dllexport) bool GetTable( TABLE_ENTRY* table )
{
    table = &global_dll_table.front();
    return true;
}

谢谢, 保罗·H

I have a C# .NET 2.0 CF project where I need to invoke a method in a native C++ DLL. This native method returns an array of type TableEntry. At the time the native method is called, I do not know how large the array will be.

How can I get the table from the native DLL to the C# project? Below is effectively what I have now.

// in C# .NET 2.0 CF project
[StructLayout(LayoutKind.Sequential)]
public struct TableEntry
{
    [MarshalAs(UnmanagedType.LPWStr)] public string description;
    public int item;
    public int another_item;
    public IntPtr some_data;
}

[DllImport("MyDll.dll", 
    CallingConvention = CallingConvention.Winapi, 
    CharSet = CharSet.Auto)]
public static extern bool GetTable(ref TableEntry[] table);

SomeFunction()
{
    TableEntry[] table = null;
    bool success = GetTable( ref table );
    // at this point, the table is empty
}


// In Native C++ DLL
std::vector< TABLE_ENTRY > global_dll_table;
extern "C" __declspec(dllexport) bool GetTable( TABLE_ENTRY* table )
{
    table = &global_dll_table.front();
    return true;
}

Thanks,
PaulH

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

哭泣的笑容 2024-08-30 21:17:35

当将未知大小的数组从本机编组到托管时,我发现最好的策略如下:

  • 在托管代码中将数组键入到 IntPtr
  • 让本机代码返回数组和大小参数。
  • 手动将数据从 IntPtr 编组到托管端的自定义结构。

因此,我将对您的代码进行以下更改。

本机:

extern "C" __declspec(dllexport) bool GetTable( TABLE_ENTRY** table, __int32* pSize )
{
    *table = &global_dll_table.front();
    *pSize = static_cast<int32>(global_dll_table.size());
    return true;
}

托管:

[DllImport("MyDll.dll", 
    CallingConvention = CallingConvention.Winapi, 
    CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.I1)]
public static extern bool GetTable(out IntPtr arrayPtr, out int size);

public static List<TableEntry> GetTable() {
  var arrayValue = IntPtr.Zero;
  var size = 0;
  var list = new List<TableEntry>();

  if ( !GetTable(out arrayValue, out size)) {
    return list; 
  }

  var tableEntrySize = Marshal.SizeOf(typeof(TableEntry));
  for ( var i = 0; i < size; i++) {  
    var cur = (TableEntry)Marshal.PtrToStructure(arrayValue, typeof(TableEntry));
    list.Add(cur);
    arrayValue = new IntPtr(arrayValue.ToInt32() + tableEntrySize);
  }
  return list;
}

When marshalling an array of unknown size from native to managed I find the best strategy is as follows

  • Type the array to IntPtr in managed code
  • Have the native code return both the array and a size parameter.
  • Manually marshal the data from IntPtr to the custom struct on the managed side.

As such I would make the following changes to your code.

Native:

extern "C" __declspec(dllexport) bool GetTable( TABLE_ENTRY** table, __int32* pSize )
{
    *table = &global_dll_table.front();
    *pSize = static_cast<int32>(global_dll_table.size());
    return true;
}

Managed:

[DllImport("MyDll.dll", 
    CallingConvention = CallingConvention.Winapi, 
    CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.I1)]
public static extern bool GetTable(out IntPtr arrayPtr, out int size);

public static List<TableEntry> GetTable() {
  var arrayValue = IntPtr.Zero;
  var size = 0;
  var list = new List<TableEntry>();

  if ( !GetTable(out arrayValue, out size)) {
    return list; 
  }

  var tableEntrySize = Marshal.SizeOf(typeof(TableEntry));
  for ( var i = 0; i < size; i++) {  
    var cur = (TableEntry)Marshal.PtrToStructure(arrayValue, typeof(TableEntry));
    list.Add(cur);
    arrayValue = new IntPtr(arrayValue.ToInt32() + tableEntrySize);
  }
  return list;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文