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?