我正在尝试做一些基本的C#\ C interop,它会返回奇怪的结果。这些是C方面的定义:
typedef struct _RESULT {
BOOL success;
char *err;
} RESULT;
typedef struct _INPUT_DATA {
char *message;
} INPUT_DATA;
API int execute_out(IN INPUT_DATA *input, OUT RESULT *result);
简单实施:
API int execute_out(INPUT_DATA *input, RESULT *result){
result = (RESULT*)malloc(sizeof RESULT);
result->err = (char*)malloc(sizeof 128);
strcpy(result->err, "Result");
result->success = TRUE;
return 0;
}
现在,我的C#定义如下:
[StructLayout(LayoutKind.Sequential)]
public struct INPUT_DATA
{
[MarshalAs(UnmanagedType.LPStr)]
public string message;
}
[StructLayout(LayoutKind.Sequential)]
public struct RESULT
{
public bool success;
public IntPtr err;
}
[DllImport("unmanaged.dll", CallingConvention = CallingConvention.Cdecl)]
public extern static int execute_out(INPUT_DATA input, out RESULT result);
当我在管理方设置这样的代码时:
Unmanaged.INPUT_DATA input = new Unmanaged.INPUT_DATA();
input.message = "Test";
Unmanaged.RESULT result;
Unmanaged.execute_out(input, out result);
我收到RESULT结构中定义的错误变量的空数据,并且我的成功标志设置不正确(产生错误)。谁能告诉我我在这里失踪了什么?
此外,与此案例相似的最佳做法是什么:
调用者(托管代码)应该为RESULT结构分配内存,然后释放它,还是应该在另一个调用中释放非托管端的已分配内存?
答案 0 :(得分:0)
根据@HansPassant和@Olaf的建议,这是适合我的实际代码:
API int execute_out(INPUT_DATA *input, RESULT *result){
//result = (RESULT*)malloc(sizeof RESULT); //this malloc is redundat which effectively replaces original pointer
result->err = (char*)malloc(sizeof 128);
strcpy(result->err, "Result");
result->success = TRUE;
return 0;
}
注释了Malloc,因为它取代了从托管代码传递的原始指针。
在管理方面,需要像下面这样声明函数:
[DllImport("unmanaged.dll", CallingConvention = CallingConvention.Cdecl)]
public extern static int execute_out(ref INPUT_DATA input, [Out] out RESULT result);
注意 ref 关键字在RESULT指针之前正确传递INPUT_DATA指针和 [Out] 属性,告诉编组我们需要回复一些东西。
最后,来自托管方的完整呼叫如下所示:
Unmanaged.INPUT_DATA input = new Unmanaged.INPUT_DATA();
input.message = "Test";
Unmanaged.RESULT result;
Unmanaged.execute_out(ref input, out result);
string error = Marshal.PtrToStringAnsi(result.err);
希望有人会觉得这很有用。