gpt4 book ai didi

c# - 具有自定义结构的 PInvoke 访问冲突异常

转载 作者:行者123 更新时间:2023-11-30 04:09:04 33 4
gpt4 key购买 nike

我正在尝试使用 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# 中,'mirror' 结构定义如下:

[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外部方法声明如下:

[DllImport(InteropUtils.RUNTIME_DLL, EntryPoint = "GetGraphicsAdapter", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool _GetGraphicsAdapter(int adapterIndex, out GraphicsAdapterDesc adapterDesc);

每当我调用 _GetGraphicsAdapter 时,我都会收到访问冲突错误(不是 AccessViolationException)。当我从 extern C++ 方法中中断程序时,一切似乎都是合式的;但是一旦我从该方法返回,就会发生访问冲突。所以,我猜想一旦该方法存在就会清理一些内存,但我看不出是什么,也不知道为什么。

话又说回来,我是 P/Invoke 的新手,也许这与我对字符串的处理有关;我不确定我的做法是否正确。

提前谢谢你。

最佳答案

您的 C# 结构 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()AdapterNameHardwareHash 转换为字符串。至于重新分配,这超出了问题的范围。

这似乎是最合理的选择。很明显,由于缓冲区的长度未在接口(interface)中传递,因此不能期望被调用方为这两个字符串分配内存。当然,字符串被声明为 const wchar_t*,这是进一步的证据。

关于c# - 具有自定义结构的 PInvoke 访问冲突异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21514489/

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