将包含 String 数组和 Integer 数组的结构传递到 C++ DLL

发布于 2024-09-03 07:31:48 字数 1145 浏览 7 评论 0原文

我在将 VB.NET 编组到 C++ 时遇到问题,代码如下:

在 C++ DLL 中:

struct APP_PARAM
{
    int numData;
    LPCSTR *text;
    int *values;
};

int App::StartApp(APP_PARAM params)
{
    for (int i = 0; i < numLines; i++)
    {
        OutputDebugString(params.text[i]);
    }
}

在 VB.NET 中:

  <StructLayoutAttribute(LayoutKind.Sequential)> _
  Public Structure APP_PARAM
    Public numData As Integer
    Public text As System.IntPtr
    Public values As System.IntPtr
  End Structure

  Declare Function StartApp Lib "AppSupport.dll" (ByVal params As APP_PARAM) As Integer

  Sub Main()

    Dim params As APP_PARAM
    params.numData = 3

    Dim text As String() = {"A", "B", "C"}
    Dim textHandle As GCHandle = GCHandle.Alloc(text)
    params.text = GCHandle.ToIntPtr(textHandle)

    Dim values As Integer() = {10, 20, 30}
    Dim valuesHandle As GCHandle = GCHandle.Alloc(values)
    params.values = GCHandle.ToIntPtr(heightHandle)

    StartApp(params)

    textHandle.Free()
    valuesHandle.Free()

  End Sub

我检查了 C++ 端,OutputDebugString 的输出是垃圾,文本数组包含随机字符。这样做的正确方法是什么?

I'm having problems with marshaling in VB.NET to C++, here's the code :

In the C++ DLL :

struct APP_PARAM
{
    int numData;
    LPCSTR *text;
    int *values;
};

int App::StartApp(APP_PARAM params)
{
    for (int i = 0; i < numLines; i++)
    {
        OutputDebugString(params.text[i]);
    }
}

In VB.NET :

  <StructLayoutAttribute(LayoutKind.Sequential)> _
  Public Structure APP_PARAM
    Public numData As Integer
    Public text As System.IntPtr
    Public values As System.IntPtr
  End Structure

  Declare Function StartApp Lib "AppSupport.dll" (ByVal params As APP_PARAM) As Integer

  Sub Main()

    Dim params As APP_PARAM
    params.numData = 3

    Dim text As String() = {"A", "B", "C"}
    Dim textHandle As GCHandle = GCHandle.Alloc(text)
    params.text = GCHandle.ToIntPtr(textHandle)

    Dim values As Integer() = {10, 20, 30}
    Dim valuesHandle As GCHandle = GCHandle.Alloc(values)
    params.values = GCHandle.ToIntPtr(heightHandle)

    StartApp(params)

    textHandle.Free()
    valuesHandle.Free()

  End Sub

I checked the C++ side, the output from the OutputDebugString is garbage, the text array contains random characters. What is the correct way to do this?

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

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

发布评论

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

评论(2

紫轩蝶泪 2024-09-10 07:31:48

GCHandle.Alloc "分配普通句柄对于指定的对象”“创建托管对象的句柄...这可以防止托管对象被收集”

您正在寻找的是 System.Runtime.InteropServices.Marshal 中的方法,这些方法允许您执行诸如将托管对象复制到非托管代码可访问的内存之类的操作。不幸的是,根据 this,指针在你的结构中,它比许多其他东西更难封送(从某种意义上说,许多其他东西可以使用适当的 P/Invoke 属性自动封送),但这仍然是可能的。我已经尝试过这个方法并且它有效:

APP_PARAM param = new APP_PARAM();
string[] text = new string[] { "A", "B", "C" };
param.numData = text.Length;

// Manually allocate an array of pointers, one for each string.  arr holds the array's address.
IntPtr arr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)) * text.Length);
try
{
  param.text = arr;

  IntPtr[] unmanagedText = new IntPtr[text.Length];
  try
  {
    // Create a null-terminated ANSI string in unmanaged memory for each element in text.
    for (int i = 0; i < text.Length; i++)
      unmanagedText[i] = Marshal.StringToHGlobalAnsi(text[i]);
    // Copy the addresses of the unmanaged strings into the manually allocated array.
    // I don't know of any way to make an unmanaged copy of a managed array in one call.
    Marshal.Copy(unmanagedText, 0, arr, unmanagedText.Length);

    // param now looks like what the C++ code is expecting (except for the array of int).
    StartApp(param);
  }
  finally
  {
    foreach (IntPtr str in unmanagedText)
      Marshal.FreeHGlobal(str);
  }
}
finally
{
  Marshal.FreeHGlobal(arr);
}

您必须为 int 值数组拥有类似的分配/释放代码,并具有自己的 try/finally 块以确保调用 FreeHGlobal。

GCHandle.Alloc "Allocates a Normal handle for the specified object", which "creates a handle to a managed object ... which prevents the managed object from being collected".

What you're looking for is the methods from System.Runtime.InteropServices.Marshal, which allow you to do things like copy managed objects to memory accessible by unmanaged code. Unfortunately, according to this, the pointers in your struct make it a little harder to marshal than many other things (in the sense that many other things can be automatically marshalled using the appropriate P/Invoke attributes), but it's still possible. I've tried this out and it works:

APP_PARAM param = new APP_PARAM();
string[] text = new string[] { "A", "B", "C" };
param.numData = text.Length;

// Manually allocate an array of pointers, one for each string.  arr holds the array's address.
IntPtr arr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)) * text.Length);
try
{
  param.text = arr;

  IntPtr[] unmanagedText = new IntPtr[text.Length];
  try
  {
    // Create a null-terminated ANSI string in unmanaged memory for each element in text.
    for (int i = 0; i < text.Length; i++)
      unmanagedText[i] = Marshal.StringToHGlobalAnsi(text[i]);
    // Copy the addresses of the unmanaged strings into the manually allocated array.
    // I don't know of any way to make an unmanaged copy of a managed array in one call.
    Marshal.Copy(unmanagedText, 0, arr, unmanagedText.Length);

    // param now looks like what the C++ code is expecting (except for the array of int).
    StartApp(param);
  }
  finally
  {
    foreach (IntPtr str in unmanagedText)
      Marshal.FreeHGlobal(str);
  }
}
finally
{
  Marshal.FreeHGlobal(arr);
}

You'll have to have similar allocation/free code for your array of int values, with its own try/finally blocks to make sure FreeHGlobal is called.

GRAY°灰色天空 2024-09-10 07:31:48

您需要使用 Marshal 类中的方法之一。

Dim str As String = "Hello World"
Dim ptr as IntPtr = Marshal.StringToHGlobalAnsi(str)
Try
  SomePInvokeCall(ptr)
Finally
  Marshal.FreeHGlobal(ptr)
End Try

You need to use one of the methods from the Marshal class.

Dim str As String = "Hello World"
Dim ptr as IntPtr = Marshal.StringToHGlobalAnsi(str)
Try
  SomePInvokeCall(ptr)
Finally
  Marshal.FreeHGlobal(ptr)
End Try
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文