借助OpenHardwareMonitor项目的一些启发,我使自己成为监视CPU和GPU指标温度,负载等的好工具。
它工作正常,但是PInvokeStackImbalance
在调用NVidia驱动程序方法时遇到警告,并且认为忽略它们是不明智的。
但是,经过数周的实验(手持NVidia Documentaion)之后,我仍然无法弄清如何以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)。
原生互操作并不容易。您需要了解谁拥有什么内存,如何分配和取消分配内存,并且需要特别注意运行的是32位还是64位。
乍一看,您在委托上缺少调用约定,因此它将默认为StdCall
。但是,根据NVAPI中的定义(对于互操作库来说,这是非常合理的),您应该使用Cdecl
:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate NvStatus NvAPI_EnumPhysicalGPUsDelegate([Out] NvPhysicalGpuHandle[] gpuHandles, out int gpuCount);
Cdecl和StdCall的棘手之处在于两者非常相似(参数从右至左传递到堆栈上,如果是整数或poitner等,则返回值以EAX表示),除了在Cdecl中,调用者负责清除堆栈,而在StdCall中,这是被调用者的工作。这意味着使用StdCall而不是Cdecl的P / Invoking几乎总是可以工作(.NET运行时会注意到堆栈不平衡并进行了修复),但是会产生警告。
如果这不能解决您的问题,请注意位数。尝试使用32位.NET应用程序中的32位库。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句