c# - 从 C# 调用非托管代码

标签 c# c

在 OpenHardwareMonitor 项目的一些启发下,我为自己制作了一个不错的小工具来监控 CPU 和 GPU 指标温度、负载等。

它工作正常,但我在调用 NVidia 驱动程序方法时遇到了 PInvokeStackImbalance 警告,我认为忽略它们是不明智的。

然而,经过数周的实验(手头有 NVidia 文档),我仍然无法弄清楚如何以 VS 2015 满意的方式定义和使用驱动程序结构和方法——这很奇怪,因为没有尽管使用完全相同的代码,但 OpenHardwareMonitor 项目中的警告。

希望这里有人能给我指出正确的方向。

[DllImport("nvapi.dll", CallingConvention = CallingConvention.Cdecl, PreserveSig = true)]
private static extern IntPtr nvapi_QueryInterface(uint id);

private delegate NvStatus NvAPI_EnumPhysicalGPUsDelegate([Out] NvPhysicalGpuHandle[] gpuHandles, out int gpuCount);
private static readonly NvAPI_EnumPhysicalGPUsDelegate NvAPI_EnumPhysicalGPUs;

NvAPI_EnumPhysicalGPUs = Marshal.GetDelegateForFunctionPointer(nvapi_QueryInterface(0xE5AC921F), typeof(NvAPI_EnumPhysicalGPUsDelegate)) as NvAPI_EnumPhysicalGPUsDelegate;

status = NvAPI_EnumPhysicalGPUs != null ? NvAPI_EnumPhysicalGPUs(PhysicalGPUHandles, out PhysicalGPUHandlesCount) : NvStatus.FUNCTION_NOT_FOUND; // warning is thrown here

最佳答案

首先,这些函数是 C 风格的,而不是 C++。这是幸运的,因为直接从 C# 与 C++ 互操作是一个巨大的痛苦(在这种情况下你真的想使用 C++/CLI)。

native 互操作并不容易。您需要了解谁拥有什么内存,如何分配和释放内存,并且需要特别注意您运行的是 32 位还是 64 位。

乍一看,您缺少对委托(delegate)的调用约定,因此它将默认为 StdCall。但是,正如 NVAPI 中所定义的(对于互操作库而言非常合理),您应该使用 Cdecl:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
private delegate NvStatus NvAPI_EnumPhysicalGPUsDelegate([Out] NvPhysicalGpuHandle[] gpuHandles, out int gpuCount);

Cdecl 和 StdCall 的棘手之处在于两者非常相似(参数在堆栈上从右到左传递,如果是整数或指针等,则返回值进入 EAX),除了在 Cdecl 中,调用者负责清除堆栈,而在 StdCall 中,这是被调用者的工作。这意味着使用 StdCall 而不是 Cdecl 的 P/Invoking 几乎总是有效(.NET 运行时注意到堆栈不平衡并修复它),但会产生警告。

如果这不能解决您的问题,请注意位数。尝试从 32 位 .NET 应用程序使用 32 位库。

关于c# - 从 C# 调用非托管代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39202455/

相关文章:

c - 有没有适用于 windows 7 64 位的汇编语言调试器

c# - 如何将空格替换为标记结尾和文本开头之间的空格

c# - 如何使用 Blazor 创建表单向导?

C# 数组和属性

c# - C# 中的 MergeSort 实现

c - 借助双指针指向第一个数组元素不起作用

c - 交换链表中的元素而不访问它?

c# - 我如何在客户端(DataServiceContext)加密 OData 请求负载并在服务器端解密请求?

Union 可以在 C 中自引用吗?

c - 如何将值保存到PIC18?