cha*_*r m 4 c# pinvoke interop native marshalling
我知道这可以通过在C中进行mallocing,将malloced指针传递给参数类型为IntPtr的委托,将编组传递给string []然后使用托管代码中的单独导出的C函数释放malloced内存来完成.
我的问题是:这可以做得更简单吗?例如:
编辑:我试过代理签名:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
MyManagedDelegate(string[] values, int valueCount)
Run Code Online (Sandbox Code Playgroud)
和C中的功能:
void NativeCallDelegate(char *pStringValues[], int nValues)
{
if (gSetStringValuesCB)
gSetStringValuesCB(pStringValues, nValues);
}
Run Code Online (Sandbox Code Playgroud)
在C中调用它:
char *Values[]= {"One", "Two", "Three"};
NativeCallDelegate(Values, 3);
Run Code Online (Sandbox Code Playgroud)
这导致我只能在数组中使用第一个字符串.
这是如何正确地完成它,我将给出一个完整的例子,以便它可以重现.
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);
}
Run Code Online (Sandbox Code Playgroud)
这里没什么好看的,我只是添加了必要的胶水代码,剩下的就是其余的.
[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);
}
Run Code Online (Sandbox Code Playgroud)
诀窍在于编组部分:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void MyManagedDelegate(
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr, SizeParamIndex = 1)]
string[] values,
int valueCount);
Run Code Online (Sandbox Code Playgroud)
该MarshalAs属性告诉.NET封送程序如下:
UnmanagedType.LPArray 你得到一个阵列......ArraySubType = UnmanagedType.LPStr ...标准C字符串......SizeParamIndex = 1 ...并且该数组的大小由第二个参数指定.System.String在调用C#方法之前,.NET编组器会复制C字符串并将其转换为实例.因此,如果您需要将动态生成的字符串传递给C#,malloc那么您可以调用它们,然后gSetStringValuesCB您可以free立即将它们全部从C代码中传递出来,因为.NET具有自己的数据副本.
你可以参考文档:
UnmanagedType.LPArray:指向C样式数组的第一个元素的指针.从托管代码编组到非托管代码时,阵列的长度由托管阵列的长度决定.当从非托管代码编组到托管代码时,数组的长度由
MarshalAsAttribute.SizeConst和MarshalAsAttribute.SizeParamIndex字段确定,当需要区分字符串类型时,可选地后跟数组中元素的非托管类型.
UnmanagedType.LPStr:单字节,以空值终止的ANSI字符串.您可以在
System.String和System.Text.StringBuilder数据类型上使用此成员.
MarshalAs.SizeParamIndex:指示包含数组元素计数的从零开始的参数,类似于
size_isCOM.
| 归档时间: |
|
| 查看次数: |
1296 次 |
| 最近记录: |