我正在尝试使用P / Invoke来填充POD结构。 C ++中的POD结构如下所示:
struct GraphicsAdapterDesc {
const wchar_t* AdapterName;
int32_t AdapterIndex;
const wchar_t* HardwareHash;
int64_t DedicatedVMEM;
int64_t DedicatedSMEM;
int64_t SharedSMEM;
int32_t NumOutputs;
};
我试着要明确指定所有字段的宽度。 C#中的“镜像”结构定义如下:
[StructLayout(LayoutKind.Sequential)]
public struct GraphicsAdapterDesc {
public WCharStringPtr AdapterName;
public int AdapterIndex;
public WCharStringPtr HardwareHash;
public long DedicatedVMEM;
public long DedicatedSMEM;
public long SharedSMEM;
public int NumOutputs;
};
WCharStringPtr
看起来像这样:
public struct WCharStringPtr {
internal IntPtr charArrayPtr;
private string asString;
public string AsString {
get {
return asString ?? (asString = Marshal.PtrToStringUni(charArrayPtr));
}
}
public static implicit operator string(WCharStringPtr operand) {
return operand.AsString;
}
public override string ToString() {
return AsString;
}
}
我有一个在C ++中定义的方法:
extern "C" __declspec(dllexport) bool GetGraphicsAdapter(int32_t adapterIndex, GraphicsAdapterDesc& outAdapterDesc) {
outAdapterDesc = RENDER_COMPONENT.GetGraphicsAdapter(adapterIndex);
return true;
}
P / Invoke extern方法声明如下:
[DllImport(InteropUtils.RUNTIME_DLL, EntryPoint = "GetGraphicsAdapter", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool _GetGraphicsAdapter(int adapterIndex, out GraphicsAdapterDesc adapterDesc);
每当我调用_GetGraphicsAdapter
时,都会收到访问冲突错误(不是AccessViolationException)。当我从外部C ++方法中破解程序时,一切似乎都是格式良好的;但是一旦从该方法返回,就会发生访问冲突。所以,我猜测一旦方法存在就会清理一些内存,但我看不清楚是什么,或者为什么。
然后,我是P / Invoke的新手,也许这与我处理字符串有关;我不确定我所做的事情是否正确。
提前谢谢。
答案 0 :(得分:2)
您的C#struct WCharStringPtr
包含两个数据成员。这些都被编组为指针。另一方面,您将其映射到的C ++字段的类型为wchar_t*
,它只是一个指针。这是一个明显的不匹配。
不清楚的是如何处理这些字符串的内存分配。调用者是分配内存还是被调用者?
假设被调用者分配内存。在这种情况下,GraphicsAdapterDesc
结构应该声明如下:
public struct GraphicsAdapterDesc {
public IntPtr AdapterName;
public int AdapterIndex;
public IntPtr HardwareHash;
public long DedicatedVMEM;
public long DedicatedSMEM;
public long SharedSMEM;
public int NumOutputs;
};
一旦函数返回,您就会调用Marshal.PtrToStringUni()
将AdapterName
和HardwareHash
转换为字符串。至于解除分配,这超出了问题的范围。
这似乎是最合理的选择。似乎很清楚,由于缓冲区的长度未在接口中传递,因此不能期望被调用者为两个字符串分配内存。当然,字符串被声明为const wchar_t*
,这是进一步的证据。