Search code examples
c#c++pinvokeguid

Error getting device handle


I have been trying to interface to a device driver for a GPS interface card. The examples that I have from the vendor are in C++. I am trying to get it working in C# using pinvoke

class HaveQuick
{
    [DllImport("setupapi.dll", CharSet = CharSet.Auto)]
    static extern IntPtr SetupDiGetClassDevs(
        ref Guid ClassGuid,
        IntPtr Enumerator,
        IntPtr hwndParent,
        uint Flags
        );

    [DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern Boolean SetupDiEnumDeviceInterfaces(
       IntPtr hDevInfo,
       ref SP_DEVINFO_DATA devInfo,
       ref Guid interfaceClassGuid,
       UInt32 memberIndex,
       ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData
    );

        Guid GUID_DEVINTERFACE_IPHQT = new Guid(0x13ff045f, 0xe9d2, 0x479c, 0xb3, 0x90, 0x8c, 0xae, 0xc7, 0xd1, 0x1c, 0xc4);
        hDeviceInfo = SetupDiGetClassDevs(ref GUID_DEVINTERFACE_IPHQT, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
        if (hDeviceInfo == IntPtr.Zero)
        {
            lastError = Marshal.GetLastWin32Error();
            Console.WriteLine("**Error: couldn't get class info error code = {0}\n");
            return;
        }

             // Find the interface for device
        devNum = 0x0000;    
        SP_DEVICE_INTERFACE_DATA interfaceData = new SP_DEVICE_INTERFACE_DATA();                // Interface data for this device
        interfaceData.cbSize = (uint)Marshal.SizeOf(interfaceData);
        SP_DEVINFO_DATA deviceInfoData = new SP_DEVINFO_DATA();
        deviceInfoData.cbSize = (uint)Marshal.SizeOf(deviceInfoData);
        success = SetupDiEnumDeviceInterfaces(hDeviceInfo, ref deviceInfoData, ref GUID_DEVINTERFACE_IPHQT, devNum, ref interfaceData);
        if (!success)
        {
            lastError = Marshal.GetLastWin32Error();
            Console.WriteLine("**Error: couldn't enum device error number = {0}\n", lastError);

}

When I run the code I get lasterror = 87 which is Invalid Parameter

If I replace with this line of code success = SetupDiEnumDeviceInterfaces(hDeviceInfo, IntPtr.Zero, ref GUID_DEVINTERFACE_IPHQT, devNum, ref interfaceData);

I get lasterror = 1784 Invlid user buffer.

Thanks for the help


Solution

  • Your SetupDiGetClassDevs prototype doesn't have SetLastError=true. So the call to Marshal.GetLastWin32Error might not be getting the correct value. Also, you shouldn't check the last error unless the value returned from the call is invalid.

    As the documentation for GetLastError says:

    You should call the GetLastError function immediately when a function's return value indicates that such a call will return useful data.

    So the pattern to use Marshal.GetLastWin32Error should be:

    IntPtr hDeviceInfo = SetupDiGetClassDevs( ... );
    if (hDeviceInfo == IntPtr.Zero)
    {
        // error here
        lastError = Marshal.GetLastWin32Error();
    }
    

    If you check the last error when there was no error, there's no telling what value you'll get. Not all functions call SetLastError with a value of 0 when they succeed. So you might be getting an error from long ago.