C# USB driver from C++

924 views Asked by At

I've a problem trying to call SetupDiEnumDeviceInterfaces from C#. It always returns 1784 error code ("The supplied user buffer is not valid for the requested operation"). On the same machine if I execute the corrisponding C++ code the function is successful. This is my C# code:

        Guid classGuid = GUID_DEVINTERFACE_DFU; // Guid(0x3fe809ab, 0xfb91, 0x4cb5, 0xa6, 0x43, 0x69, 0x67, 0x0d, 0x52,0x36,0x6e)

        IntPtr hDevInfo = Win32.SetupDiGetClassDevs(ref classGuid, IntPtr.Zero, IntPtr.Zero, Win32.DIGCF_DEVICEINTERFACE | Win32.DIGCF_PRESENT);
        if (hDevInfo.ToInt32() == Win32.INVALID_HANDLE_VALUE)
        {
            Console.WriteLine("read hardware information error");
        }
        else
        {
            uint i = 0;
            SP_DEVINFO_DATA devInfoData = new SP_DEVINFO_DATA();
            devInfoData.classGuid = Guid.Empty;
            devInfoData.devInst = 0;
            devInfoData.reserved = IntPtr.Zero;

            bool result = Win32.SetupDiEnumDeviceInfo(hDevInfo, i, devInfoData);
            if (false == result)
            {
                int error = Marshal.GetLastWin32Error();
                if (error != Win32.ERROR_NO_MORE_ITEMS)
                    throw new Win32Exception(error);
            }

            SP_DEVICE_INTERFACE_DATA ifData = new SP_DEVICE_INTERFACE_DATA();
            ifData.cbSize = 50;
            ifData.Flags = 0;
            ifData.InterfaceClassGuid = Guid.Empty;
            ifData.Reserved = IntPtr.Zero;

            bool result2 = Win32.SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, ref classGuid, i, ref ifData);
            if(result2 == false)
            {
                int error = Marshal.GetLastWin32Error();
                if (error != Win32.ERROR_NO_MORE_ITEMS)
                    throw new Win32Exception(error);
            }
        }


[StructLayout(LayoutKind.Sequential)]
public class SP_DEVINFO_DATA
{
    public uint cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
    public Guid classGuid;
    public uint devInst;
    public IntPtr reserved;
};

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public class SP_DEVICE_INTERFACE_DATA
{
    public uint cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));
    public Guid InterfaceClassGuid;
    public uint Flags;
    public IntPtr Reserved;
}

public class Win32
{
    [DllImport("setupapi.dll", SetLastError = true)]
    public static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, IntPtr Enumerator, IntPtr hwndParent, uint Flags);   

    [DllImport("setupapi.dll", SetLastError = true)]
    public static extern Boolean SetupDiEnumDeviceInfo(IntPtr lpInfoSet, UInt32 dwIndex, SP_DEVINFO_DATA devInfoData);

    public const int DIGCF_PRESENT = 0x02;
    public const int DIGCF_DEVICEINTERFACE = 0x10;
    public const long ERROR_NO_MORE_ITEMS = 259L;
}

And this is my C++ code:

    GUID Guid=GUID_DFU;  // { 0x3fe809ab, 0xfb91, 0x4cb5, { 0xa6, 0x43, 0x69, 0x67, 0x0d, 0x52,0x36,0x6e } }
    HDEVINFO info = SetupDiGetClassDevs(&Guid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
    if (info!=INVALID_HANDLE_VALUE)  
    {
        SP_INTERFACE_DEVICE_DATA ifData;
        ifData.cbSize=sizeof(ifData);

        bool result = SetupDiEnumDeviceInterfaces(info, NULL, &Guid, devIndex, &ifData);
    }

The code is running on Windows 8.1 x64 and the C# application platform is x86.

1

There are 1 answers

5
David Heffernan On BEST ANSWER

You declare SP_DEVICE_INTERFACE_DATA to be a class in the C# code. That means that it is already a reference. You then pass the SP_DEVICE_INTERFACE_DATA instance by reference to SetupDiEnumDeviceInfo. Which means that you are passing SP_DEVICE_INTERFACE_DATA** rather than SP_DEVICE_INTERFACE_DATA*, in C++ terms.

Either:

  1. Change SP_DEVICE_INTERFACE_DATA to be a struct, or
  2. Leave SP_DEVICE_INTERFACE_DATA as a class, but pass it by value. That is, as you did with SP_DEVINFO_DATA and SetupDiEnumDeviceInfo.

You are setting cbSize incorrectly. It should be:

ifData.cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));

There's no point in setting the other members of SP_DEVICE_INTERFACE_DATA since they are ignored by the function that you call. That function's job is to populate those members.

There may be other problems. It's hard to say because you have not posted your actual code. The C++ code does not compile, and the C# code is incomplete.