使用TCHAR ** x []参数从C#编组到DLL

时间:2013-01-28 12:59:01

标签: c# .net dll marshalling dllimport

我试图从一些C#调用Win32 DLL。 DLL函数声明如下:

extern "C" __declspec(dllexport) UINT foo(TCHAR** list[], int& listSize, TCHAR* error);

在C#中,我声明外部函数如下:

[DllImport("foo.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
static extern uint foo(StringBuilder[] list, ref int listSize, StringBuilder error);

我的问题与 list 参数有关,该参数是一个StringBuilder类的数组。

我调用DLL函数的一些测试代码如下: (注意:我意识到缺少边界检查等。在这个阶段,我只是想让事情发挥作用)。

// allocate a buffer for a possible error message being returned
StringBuilder error = new StringBuilder(1000);

// allocate buffers for the list of strings returned
StringBuilder[] list = new StringBuilder[10];
for (int i = 0; i < 10; i++)
{
    list[i] = new StringBuilder(1000);
}

int listSize = list.Length;

uint result = foo(list, ref listSize, error);

将StringBuilder作为错误参数的缓冲区传递,工作正常。我可以按如下方式在DLL中设置其内容:

_tcscpy(error, _T("Something went wrong");

当C#调用 foo 返回时,字符串错误变量包含我们在DLL中设置的文本。

但是,我无法弄清楚如何编组 StringBuilder [] list 参数。

在C ++中,我可以设置 list 数组的内容:

_tcscpy((*list)[0], _T("First item")); 
// and so on...

并且,即使由于任何可能有问题的编组而没有发生崩溃,C#中的列表,当对 foo()的调用返回时,不包含我们在C ++中设置的任何字符串。

我猜测问题出在 DllImport 上,以及我如何宣布 list 参数应该被编组。

顺便说一下,示例DLL有一个匹配函数,然后调用该函数来解除分配上面显示的示例 foo 返回的“TCHAR **列表”。

2 个答案:

答案 0 :(得分:0)

我暂时没有这样做,但你应该尝试以下方法来正确编组数组列表

添加一个 [MarshalAs(UnmanagedType.LPArray, ArraySubType.LPTStr, SizeParamIndex=1)] 属性为 list ,您应该添加out,因为数据是用C ++代码分配的。

答案 1 :(得分:0)

好的,我找到了解决问题的方法。看起来答案在于 IntPtr 。 C函数在“TCHAR ** list []”中创建并返回了一个字符串数组。

首先,我将C#中的声明更改为:

[DllImport("foo.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
static extern uint foo(out IntPtr[] list, ref int listSize, StringBuilder error);

然后,当对DLL的调用返回时,我需要从数组中提取字符串:

string[] returnedList = new string[listSize];
IntPtr[] ptrArray = new IntPtr[listSize];

Marshal.Copy(list, ptrArray, 0, listSize);

for (int i = 0; i < listSize; i++)
{
    returnedList[i] = Marshal.PtrToStringAuto(ptrArray[i]);
}

这导致从C DLL中获取字符串数组。