2016-08-29 3 views
1

С вдохновение от проекта OpenHardwareMonitor я сделал себе хороший гаджет для мониторинга CPU и метрики GPU температуры, нагрузки и т.д.Вызов неуправляемого кода из C#

Он отлично работает, но я бегу в к PInvokeStackImbalance предупреждения при вызове методов драйвера NVidia и не думаю, что их игнорировать не стоит.

Однако после нескольких недель экспериментов (с поддержкой NVidia Documentaion) я до сих пор не могу понять, как определить и использовать Drivers Structs and Methods таким образом, чтобы 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-style, а не 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 - это задача вызываемого. Это означает, что P/Invoking с StdCall вместо Cdecl почти всегда будет работать (среда выполнения .NET замечает дисбаланс стека и исправляет его), но выдает предупреждение.

Если это не поможет решить вашу проблему, обратите внимание на битту. Попробуйте использовать 32-битную библиотеку из 32-разрядного приложения .NET.

+0

Bingo! Я не знал, что вы можете указать соглашение о вызовах для делегатов, я добавил это всем делегатам и не стал больше предупреждать! – VikFreeze

Смежные вопросы