2016-08-29 32 views
1

非托管代码与来自所述OpenHardwareMonitor项目,我已经自己做了一个漂亮的小工具来监视CPU和GPU指标温度,负载一些启示等调用从C#

它工作正常,但我到一个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 

回答

0

首先,功能是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棘手的是,这两个非常相似(参数都在栈上传递从右到左,返回值在EAX中,如果是整数或poitner等),除了在Cdecl中,调用者负责清除堆栈,而在StdCall中,它是被调用者的工作。这意味着使用StdCall而不是Cdecl的P /调用几乎总是能够工作的(.NET运行时会注意到堆栈不平衡并修复它),但会产生警告。

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

+0

宾果!我不知道你可以在代表中指定调用约定,我将它添加到所有代表中,不再有任何警告! – VikFreeze