Question

I'd like to programmatically install the MS loopback adapter to automate tunneling of SMB over SSH.

All the code I found on the net uses the MS devcon utility, which is not redistributable (cf. http://support.microsoft.com/kb/311272/en-us). Example usage (more examples):

devcon -r install %WINDIR%\Inf\Netloop.inf *MSLOOP

Apart from the distributability issue, ideally i'd like to have some control over the resulting device name, though that could be fixed by enumerating the network adapters before and after and looking for the new MS loopback device. That's a bit racy, though I think I could live with it. My idea is to adapt some of this code.

I'm currently looking into the devcon source code from the WDK to add the loopback adapter via SetupAPI/CfgMgr32 as the MS KB article linked above suggests. Is there any easier/scriptable way?

If there is none, does anyone have some relatively simple sample code for that SetupAPI/CfgMgr32 route?

Was it helpful?

Solution

I wanted to achieve the same thing without writing any new exe to do it and found it can be done with cscript and the devcon and netsh tools. creating the adapter seems to give you no control over what it will be called, so you have to enumerate using the WMI interface after you have created it. Unfortunately netsh behaviour depends on which version of windows you're on, but bung the following in a file called create-loopback.vbs and it will work on XP and 2008 server.

  Dim strLastLoopbackAdapterName, loopbackAdapterName 

  If wscript.arguments.count < 3 then
    WScript.Echo "usage: create-loopback.vbs loopbackAdapterName loopbackIpAddress loopbackSubNetMask "
    WScript.Quit
  end If
  loopbackAdapterName = wscript.arguments(0)
  loopbackIpAddress = wscript.arguments(1)
  loopbackSubNetMask = wscript.arguments(2)

  Wscript.Echo "Creating loopback called " &loopbackAdapterName &" on " &loopbackIpAddress &" with mask " &loopbackSubNetMask

  Set objShell = CreateObject("WScript.Shell") 
  Wscript.Echo "Installing loopback adapter..."

  objShell.Run "cmd /c devcon install %windir%\inf\netloop.inf *MSLOOP", 0, True 

  Wscript.Echo "Waiting for drivers to update..."
  Wscript.sleep 10000 'Allow 10s for install' 

  strComputer = "."
  Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2")
  Set colItems = objWMIService.ExecQuery("SELECT NetConnectionID FROM Win32_NetworkAdapter WHERE Name='Microsoft Loopback Adapter'", "WQL", 48)
  For Each objItem In colItems
     strLastLoopbackAdapterName = objItem.NetConnectionID
  Next

  Wscript.Echo "Last Loopback Connection is " & strLastLoopbackAdapterName  

  Wscript.Echo "Renaming new loopback..."
  objShell.Run "netsh interface set interface name = " &Chr(34) &strLastLoopbackAdapterName &Chr(34) &" newname = " &Chr(34) &loopbackAdapterName &Chr(34), 0, True 
  Wscript.Echo "Configuring loopback..."
  objShell.run "netsh interface ip set address name=" &Chr(34) &loopbackAdapterName &Chr(34) &" source=static " &loopbackIpAddress &" " &loopbackSubNetMask, 0, True 
  Wscript.Echo "Done"
  WScript.Quit(0)

OTHER TIPS

Please check the following thread:

How Do I Install Hardware Driver Using C on Win32

Hope i'm not too late for the party - doing it without devcon/vbs is possible (though many native pinvoke calls are required):

In order to install the loopback adapter, call the following method with the parameters "C:\Windows\Inf\netloop.inf", *MSLOOP:

class Devcon
{
    //https://msdn.microsoft.com/en-us/magazine/dd419661.aspx?f=255&MSPPError=-2147217396#id0070035
    [HandleProcessCorruptedStateExceptions]
    static bool InstallDriver(string inf, string hwid)
    {
        StringBuilder className = new StringBuilder(MAX_CLASS_NAME_LEN);
        Guid ClassGUID = Guid.Empty;

        if (!SetupDiGetINFClass(inf, ref ClassGUID, className, MAX_CLASS_NAME_LEN, 0))
            return false;

        IntPtr DeviceInfoSet = SetupDiCreateDeviceInfoList(ref ClassGUID, IntPtr.Zero);
        SP_DEVINFO_DATA DeviceInfoData = new SP_DEVINFO_DATA();
        if (!SetupDiCreateDeviceInfo(DeviceInfoSet, className.ToString(), ref ClassGUID, null, IntPtr.Zero, DICD_GENERATE_ID, DeviceInfoData))
            return false;

        if (!SetupDiSetDeviceRegistryProperty(DeviceInfoSet, DeviceInfoData, SPDRP_HARDWAREID, hwid, hwid.Length))
        {
            SetupDiDestroyDeviceInfoList(DeviceInfoSet);
            return false;
        }

        if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, DeviceInfoSet, DeviceInfoData))
        {
            SetupDiDestroyDeviceInfoList(DeviceInfoSet);
            return false;
        }

        // http://stackoverflow.com/questions/11474317/updatedriverforplugandplaydevices-error-is-telling-me-im-not-doing-something
        try
        {
            bool reboot = false;
            if (!UpdateDriverForPlugAndPlayDevices(IntPtr.Zero, hwid, inf, 0, reboot))
            {
                SetupDiCallClassInstaller(DIF_REMOVE, DeviceInfoSet, DeviceInfoData);
                return false;
            }
        }
        catch (AccessViolationException) { }
        return true;
    }

    // Consts
    const int MAX_CLASS_NAME_LEN = 32;
    const int SPDRP_HARDWAREID = 0x00000001;
    const int DICD_GENERATE_ID = 0x00000001;
    const int DIF_REGISTERDEVICE = 0x00000019;
    const int DIF_REMOVE = 0x00000005;

    // Pinvokes
    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiGetINFClass(string infName, ref Guid ClassGuid, [MarshalAs(UnmanagedType.LPStr)] StringBuilder ClassName, int ClassNameSize, int RequiredSize);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern IntPtr SetupDiCreateDeviceInfoList(ref Guid ClassGuid, IntPtr hwndParent);

    [DllImport("Setupapi.dll", SetLastError = true)]
    static extern bool SetupDiCreateDeviceInfo(IntPtr DeviceInfoSet, String DeviceName, ref Guid ClassGuid, string DeviceDescription, IntPtr hwndParent, Int32 CreationFlags, SP_DEVINFO_DATA DeviceInfoData);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiSetDeviceRegistryProperty(IntPtr DeviceInfoSet, SP_DEVINFO_DATA DeviceInfoData, uint Property, string PropertyBuffer, int PropertyBufferSize);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiCallClassInstaller(UInt32 InstallFunction, IntPtr DeviceInfoSet, SP_DEVINFO_DATA DeviceInfoData);

    [DllImport("newdev.dll", SetLastError = true)]
    static extern bool UpdateDriverForPlugAndPlayDevices(IntPtr hwndParent, string HardwareId, string FullInfPath, int InstallFlags, bool bRebootRequired);

    // Structs
    [StructLayout(LayoutKind.Sequential, Pack = 8)]
    class SP_DEVINFO_DATA
    {
        internal int cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
        [MarshalAs(UnmanagedType.Struct)]
        internal Guid classGuid = Guid.Empty; // temp
        internal int devInst = 0; // dumy
        internal long reserved = 0;
    }
}

The above will work on x64 OSs. in order for it to work on x86 OSs, change Pack = 8 to Pack = 1 in the SP_DEVINFO_DATA struct

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top