Reputation: 7227
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?
Upvotes: 3
Views: 4050
Reputation: 6553
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
Upvotes: 2
Reputation: 342
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)
Upvotes: 4
Reputation: 9985
Please check the following thread:
How Do I Install Hardware Driver Using C on Win32
Upvotes: 2