C# 自定义结构的PInvoke访问冲突异常
我正在尝试使用p/Invoke来填充一个POD结构。C++中的POD结构看起来像这样:C# 自定义结构的PInvoke访问冲突异常,c#,c++,pinvoke,access-violation,C#,C++,Pinvoke,Access Violation,我正在尝试使用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; in
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;
};
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;
}
}
public struct GraphicsAdapterDesc {
public IntPtr AdapterName;
public int AdapterIndex;
public IntPtr HardwareHash;
public long DedicatedVMEM;
public long DedicatedSMEM;
public long SharedSMEM;
public int 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;
};
[DllImport(InteropUtils.RUNTIME_DLL, EntryPoint = "GetGraphicsAdapter", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool _GetGraphicsAdapter(int adapterIndex, out GraphicsAdapterDesc adapterDesc);
其中,WCharStringPtr
如下所示:
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;
};
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;
}
}
public struct GraphicsAdapterDesc {
public IntPtr AdapterName;
public int AdapterIndex;
public IntPtr HardwareHash;
public long DedicatedVMEM;
public long DedicatedSMEM;
public long SharedSMEM;
public int NumOutputs;
};
我在C++中定义了这样一个方法:
extern "C" __declspec(dllexport) bool GetGraphicsAdapter(int32_t adapterIndex, GraphicsAdapterDesc& outAdapterDesc) {
outAdapterDesc = RENDER_COMPONENT.GetGraphicsAdapter(adapterIndex);
return true;
}
p/Invoke extern方法声明如下:
[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;
};
[DllImport(InteropUtils.RUNTIME_DLL, EntryPoint = "GetGraphicsAdapter", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool _GetGraphicsAdapter(int adapterIndex, out GraphicsAdapterDesc adapterDesc);
无论何时调用
\u GetGraphicsAdapter
,我都会收到一个访问冲突错误(不是AccessViolationException)。当我从外部C++程序中中断程序时,一切看起来都很好;但一旦我从该方法返回,访问冲突就会发生。所以,我猜一旦该方法存在,就会有一些内存被清除,但我不知道是什么,或者为什么
再说一次,我对p/Invoke还不熟悉,也许这与我对字符串的处理有关;我不确定我所做的是否正确
提前感谢。您的C#structWCharStringPtr
包含两个数据成员。它们都被编组为指针。另一方面,您将此字段映射为C++类型:代码> WCARGET**/COD>,这只是一个指针。所以这是一个明显的不匹配
不清楚的是如何处理这些字符串的内存分配。调用者分配内存,还是被调用者分配内存
假设被调用方分配内存。在这种情况下,GraphicsAdapterDesc
struct应该这样声明:
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;
};
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;
}
}
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\u t*
,这是进一步的证据 你在这两方面都是正确的;预计在调用时已分配内存。