1

I know this sounds really strange, but I don't know how to even ask this properly. I've been trying to P/Invoke into NVidia's NVML library with limited success: I've managed to call a few of the APIs exported by that library

Now I am trying to call nvmlDeviceGetHandleByIndex_v2 but I've been stuck for a long while on this one. It takes in a nvmlDevice_t pointer, but I've found nothing on what nvmlDevice_t actually is beyond this header definition:

typedef struct nvmlDevice_st* nvmlDevice_t;

The problem is that the header file does not make any other reference to nvmlDevice_st so I don't know how much heap space to allocate for it, if any. I've found this official C++ example that calls that same function like this:

nvmlDevice_t device;
CheckNVMLErrors(nvmlDeviceGetHandleByIndex(device_index, &device));

My main problem is that I'm not familiar enough with C/C++ to understand the implicit mechanics/memory allocation done by the device declaration, and the nvml.h header does not define what nvmlDevice_st actually is.

I tried calling it with a ref int parameter (with an initial 0 value) and apparently it does work but I want to understand why, if possible. For reference, the value of that ref int parameter after the call was 1460391512, in case something can be gleamed off that.

Machinarius
  • 3,637
  • 3
  • 30
  • 53
  • hi, interesting, not sure if this might be of help https://stackoverflow.com/questions/17084272/passing-a-struct-containing-an-int-array-of-unknown-size-from-c-sharp-to-c-and-b – IronMan Feb 18 '21 at 23:29
  • 2
    If you look at the source, that is just an internal pointer used by the SDK. The value it points to has no meaning to you. You use it to identify a device you are working with. Think `Handle` or `HWND` in windows. You call something like `FindWindow()`, it returns what seems to be a random value back to you. You don't care what that value holds, you just use that value to identify that window when you call `GetWindowText()` or any other windowing methods. – Andy Feb 18 '21 at 23:38
  • 3
    It is IntPtr, not int. Hiding the implementation behind a *handle* is a very old mechanism to encourage language independence and avoid api abuse. Your OS uses them heavily. Google "handle based api" to learn more, the answers in [this SE question](https://softwareengineering.stackexchange.com/questions/294761/why-use-an-opaque-handle-that-requires-casting-in-a-public-api-rather-than-a-t) are not great, but may help to get the lay of the land. – Hans Passant Feb 18 '21 at 23:43
  • I tried to call it as `ref IntPtr` with a variable initialized to `IntPtr.Zero` assuming it was a handle but I got back an Invalid Parameter error :( @HansPassant @Andy – Machinarius Feb 18 '21 at 23:54
  • 1
    try `out IntPtr` – Andy Feb 18 '21 at 23:57
  • That was exactly it, thank you! Add an answer so I can properly flag it please @Andy – Machinarius Feb 18 '21 at 23:59

1 Answers1

3

If you look at the source, that is just an internal pointer used by the SDK. The value it points to has no meaning to you. You use it to identify a device you are working with.

Think Handle or HWND in Windows. You call something like FindWindow(), it returns what seems to be a random value back to you. You don't care what that value holds, you just use that value to identify that window when you call GetWindowText() or any other windowing methods.

So, you are on the right track with using ref int, but what you want is a pointer. So you should use out IntPtr to get the value.

Andy
  • 12,859
  • 5
  • 41
  • 56
  • 1
    To expand a bit on your answer, this is the final DllImport declaration: `[DllImport("nvidia-ml.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "nvmlDeviceGetHandleByIndex_v2")] public static extern ReturnCodes GetDeviceHandleByIndex(int index, out IntPtr handle);` – Machinarius Feb 19 '21 at 00:01
  • 1
    @Machinarius -- excellent, glad it worked out :) I love doing that kind of stuff. Reverse engineering is a ton of fun. – Andy Feb 19 '21 at 00:03