我在与在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的输出是垃圾,文本数组包含随机字符。 什么是这样做的正确方法?
GCHandle.Alloc
“则分配指定的对象正常处理” ,其中“创建一个句柄管理对象......这防止了管理对象被收集”。
什么你要找的是从方法System.Runtime.InteropServices.Marshal
,它允许你做的事情一样复制管理对象由非托管代码访问内存。 不幸的是,根据这个 ,在你的结构指针使它更难一点元帅比许多其他的事情(在这个意义上,许多其他的事情可以使用相应的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被调用。
您需要使用从方法之一Marshal
类。
Dim str As String = "Hello World"
Dim ptr as IntPtr = Marshal.StringToHGlobalAnsi(str)
Try
SomePInvokeCall(ptr)
Finally
Marshal.FreeHGlobal(ptr)
End Try
文章来源: Passing a Structure containing an array of String and an array of Integer into a C++ DLL