简体   繁体   English

从C#调用非托管代码

[英]Calling unmanaged Code from C#

With some inspiration from the OpenHardwareMonitor Project i have made myself a nice gadget to monitor CPU and GPU metrics Temperature, Load, etc. 借助OpenHardwareMonitor项目的一些灵感,我使自己成为一个很好的小工具来监控CPU和GPU指标温度,负载等。

It works fine but I am running in to a PInvokeStackImbalance warning when calling the NVidia Driver Methods and don't think is wise to ignore them. 它工作正常但我在调用NVidia驱动程序方法时遇到了PInvokeStackImbalance警告,并且认为忽略它们是不明智的。

However after weeks of experimentation (with NVidia Documentaion in hand) I still can't figure out how to define and use the Drivers Structs and Methods in such a way that VS 2015 is happy with - Which is strange because there are no warnings in the OpenHardwareMonitor Project despite using the exact same code. 然而,经过数周的实验(手持NVidia Documentaion),我仍然无法弄清楚如何以VS 2015满意的方式定义和使用驱动程序结构和方法 - 这很奇怪,因为没有警告OpenHardwareMonitor项目尽管使用完全相同的代码。

Hopefully someone here can point me in the right direction. 希望有人能指出我正确的方向。

[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

First, the functions are C-style, not C++. 首先,函数是C风格,而不是C ++。 Which is fortunate, since interoping with C++ directly from C# is a huge pain (you'd really want to use C++/CLI in that case). 这是幸运的,因为直接从C#中使用C ++是一个巨大的痛苦(在这种情况下你真的想要使用C ++ / CLI)。

Native interop is not easy. 原生互操作并不容易。 You need to understand who owns what memory, how to allocate and deallocate it, and you need to pay a lot of attention to whether you're running 32-bit or 64-bit. 你需要了解谁拥有什么内存,如何分配和解除分配,你需要注意你是在运行32位还是64位。

At first glance, you're missing a calling convention on the delegate, so it will default to StdCall . 乍一看,您在委托上缺少调用约定,因此它将默认为StdCall However, as defined in NVAPI (and as very reasonable for interop libraries), you are supposed to use Cdecl : 但是,正如NVAPI中定义的那样(并且对于互操作库来说非常合理),您应该使用Cdecl

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

The tricky thing with Cdecl and StdCall is that both are very similar (the arguments are passed on stack right-to-left, the return value goes in EAX if integer or poitner etc.), except that in Cdecl, the caller is responsible for clearing the stack, while in StdCall, it's the callee's job. 使用Cdecl和StdCall的棘手问题是两者非常相似(参数在堆栈中从右向左传递,返回值在EAX中传递,如果是整数或者poitner等),除了在Cdecl中,调用者负责清除堆栈,而在StdCall中,这是被调用者的工作。 This means that P/Invoking with StdCall instead of Cdecl will almost always work (the .NET runtime notices the stack imbalance and fixes it), but will produce a warning. 这意味着使用StdCall而不是Cdecl进行P / Invoking几乎总是有效(.NET运行时会注意到堆栈不平衡并修复它),但会产生警告。

If this doesn't solve your problem, pay attention to the bitness. 如果这不能解决您的问题,请注意位数。 Try using the 32-bit library from a 32-bit .NET application. 尝试使用32位.NET应用程序中的32位库。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM