How to force a generic Microsoft driver programmatically (RNDIS) with setupapi DiInstallDevice if it fails with ERROR_INVALID_PARAMETER?

1

When I plug a USB RNDIS device (Linux gadget) to a Windows PC, is seen as 'RNDIS' device, without driver. To make it work I go to Device Manager, and manually select the Microsoft Generic Remote RNDIS Driver.

My final goal was to force-install that generic Microsoft driver from code (C#), to avoid users to do it manually. I tried devcon, pnputil and other ways, but nothing worked. Finally I implemented a pinvoke for DiInstallDevice Windows SetupAPI.

    [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, [MarshalAs(UnmanagedType.LPTStr)] string Enumerator, IntPtr hwndParent, uint Flags);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet, uint MemberIndex, ref SP_DEVINFO_DATA DeviceInfoData);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiEnumDriverInfo(IntPtr DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, int driverType, int MemberIndex, ref SP_DRVINFO_DATA drvinfo);

    [DllImport("newdev.dll", SetLastError = true)]
    public static extern bool DiInstallDevice(
        IntPtr hwndParent,
        IntPtr deviceInfoSet,
        ref SP_DEVINFO_DATA DeviceInfoData,
        ref SP_DRVINFO_DATA DriverInfoData,
        DiFlags Flags,
        ref bool NeedReboot);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiBuildDriverInfoList(
        IntPtr deviceInfoSet,
        ref SP_DEVINFO_DATA deviceInfoData,
        int DriverType);

...

    public static void ForceRNDISDriver(IntPtr hwndParent)
    {
        var nullguid = Guid.Empty;
        IntPtr deviceInfoSet = SetupDiGetClassDevs(ref nullguid, null, IntPtr.Zero, (uint)(DiGetClassFlags.DIGCF_ALLCLASSES)); //all devices
        if (deviceInfoSet.ToInt64() != -1 && deviceInfoSet.ToInt64() != 0)
        {
            uint BUFFER_SIZE = 32000;
            byte[] ptrBuf = new byte[BUFFER_SIZE];

            SP_DEVINFO_DATA deviceInfoData = new SP_DEVINFO_DATA();
            deviceInfoData.cbSize = (uint)Marshal.SizeOf(deviceInfoData);
            SP_DRVINFO_DATA driverInfoData = new SP_DRVINFO_DATA();
            driverInfoData.cbSize = Marshal.SizeOf(driverInfoData);
            bool Success = true;
            uint i = 0;
            while (Success)
            {
                // start the enumeration searching for hardware ID
                Success = SetupDiEnumDeviceInfo(deviceInfoSet, i, ref deviceInfoData);
                if (Success)
                {
                    if (SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref deviceInfoData, (uint)SetupDiGetDeviceRegistryPropertyEnum.SPDRP_HARDWAREID, out uint RegType, ptrBuf, BUFFER_SIZE, out uint RequiredSize))
                    {
                        string hwid = Encoding.Unicode.GetString(ptrBuf, 0, (int)RequiredSize - 2);
                        if (hwid.ToUpper().Contains("HARDWAREIDEXAMPLE"))
                        {
                            int SPDIT_NODRIVER = 0x00000000;
                            int SPDIT_CLASSDRIVER = 0x00000001;
                            int SPDIT_COMPATDRIVER = 0x00000002;

                            bool built = SetupDiBuildDriverInfoList(deviceInfoSet, ref deviceInfoData, SPDIT_CLASSDRIVER);
                            if (built)
                            {
                                int di = 0;
                                while (true)
                                {
                                    bool enumed = SetupDiEnumDriverInfo(deviceInfoSet, ref deviceInfoData, SPDIT_CLASSDRIVER, di++, ref driverInfoData);
                                    if (enumed)
                                    {
                                        if (driverInfoData.Description.ToUpper().Contains("NDIS"))
                                        {
                                            break;
                                        }
                                    }
                                    else
                                        break;
                                }
                            }
                            break;
                        }
                    }
                }
                i++;
            }


            bool reboot = true;
            bool dii = DiInstallDevice(hwndParent,
                deviceInfoSet,
                ref deviceInfoData,
                ref driverInfoData,
                DiFlags.DIIDFLAG_INSTALLNULLDRIVER,
                ref reboot);
            int le = GetLastError();//87: INVALID_PARAMETER

        }
    }

I can retrieve both deviceInfoData and driverInfoData, with meaningful data inside.

The final call to DiInstallDevice always fail with last error 87: ERROR_INVALID_PARAMETER. Am I'm missing something? Is there any other way to select a generic driver for an unrecognized device?

c#
setupapi
rndis
asked on Stack Overflow Jan 21, 2021 by StefanoV

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0