【问题标题】:Passing a Structure containing an array of String and an array of Integer into a C++ DLL将包含字符串数组和整数数组的结构传递到 C++ DLL
【发布时间】:2010-05-27 06:50:06
【问题描述】:

我在将 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 的输出是垃圾,文本数组包含随机字符。这样做的正确方法是什么?

【问题讨论】:

    标签: c++ vb.net arrays marshalling structure


    【解决方案1】:

    GCHandle.Alloc"Allocates a Normal handle for the specified object"“创建一个托管对象的句柄......这会阻止托管对象被收集”

    您正在寻找来自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。

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        猜你喜欢
        • 2011-06-01
        • 2010-12-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-13
        • 1970-01-01
        相关资源
        最近更新 更多