gpt4 book ai didi

c# - 如何调用 C# 委托(delegate)以从 native C 最简单的方式传递字符串数组?

转载 作者:太空狗 更新时间:2023-10-30 00:49:49 27 4
gpt4 key购买 nike

我知道这可以通过在 C 中进行 mallocing 来完成,将 malloced 指针传递给参数类型为 IntPtr 的委托(delegate),编码为 string[],然后使用单独的、从托管代码导出的 C 函数释放 malloced 内存。

我的问题是:这可以用更简单的方式完成吗?例如。 :

  • C# 委托(delegate)参数是字符串[]类型?
  • 没有单独的自由函数可以从托管代码中调用

编辑:我尝试使用委托(delegate)签名:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
MyManagedDelegate(string[] values, int valueCount)

和 C 中的函数:

void NativeCallDelegate(char *pStringValues[], int nValues)
{
if (gSetStringValuesCB)
gSetStringValuesCB(pStringValues, nValues);
}

在 C 中调用它:

char *Values[]= {"One", "Two", "Three"};
NativeCallDelegate(Values, 3);

这导致我只能使用数组中的第一个字符串。

最佳答案

下面是如何正确地做到这一点,我将给出一个完整的例子,以便它可以重现。

C端

typedef void(*setStringValuesCB_t)(char *pStringValues[], int nValues);

static setStringValuesCB_t gSetStringValuesCB;

void NativeCallDelegate(char *pStringValues[], int nValues)
{
if (gSetStringValuesCB)
gSetStringValuesCB(pStringValues, nValues);
}

__declspec(dllexport) void NativeLibCall(setStringValuesCB_t callback)
{
gSetStringValuesCB = callback;
char *Values[] = { "One", "Two", "Three" };
NativeCallDelegate(Values, 3);
}

这里没什么特别的,我只是添加了必要的胶水代码,剩下的就不用管了。

C# 方面

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void MyManagedDelegate(
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr, SizeParamIndex = 1)]
string[] values,
int valueCount);

[DllImport("NativeTemp", CallingConvention = CallingConvention.Cdecl)]
public static extern void NativeLibCall(MyManagedDelegate callback);

public static void Main()
{
NativeLibCall(PrintReceivedData);
}

public static void PrintReceivedData(string[] values, int valueCount)
{
foreach (var item in values)
Console.WriteLine(item);
}

诀窍在于编码部分:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void MyManagedDelegate(
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr, SizeParamIndex = 1)]
string[] values,
int valueCount);

MarshalAs 属性告诉 .NET 编码(marshal)拆收器以下信息:

  • UnmanagedType.LPArray 您正在获取一个数组...
  • ArraySubType = UnmanagedType.LPStr ...标准 C 字符串...
  • SizeParamIndex = 1 ...并且该数组的大小由第二个参数指定。

在调用 C# 方法之前,.NET 编码(marshal)拆收器将 C 字符串复制并转换为 System.String 实例。因此,如果您需要将动态生成的字符串传递给 C#,您可以malloc 它们,然后您调用 gSetStringValuesCB,然后您可以立即释放它们,全部来自 C 代码,因为 .NET 有自己的数据副本。


可以引用the docs :

UnmanagedType.LPArray:

A pointer to the first element of a C-style array. When marshaling from managed to unmanaged code, the length of the array is determined by the length of the managed array. When marshaling from unmanaged to managed code, the length of the array is determined from the MarshalAsAttribute.SizeConst and MarshalAsAttribute.SizeParamIndex fields, optionally followed by the unmanaged type of the elements within the array when it is necessary to differentiate among string types.

UnmanagedType.LPStr:

A single byte, null-terminated ANSI character string. You can use this member on the System.String and System.Text.StringBuilder data types.

MarshalAs.SizeParamIndex:

Indicates the zero-based parameter that contains the count of array elements, similar to size_is in COM.

关于c# - 如何调用 C# 委托(delegate)以从 native C 最简单的方式传递字符串数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35986459/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com