When i try to remove my NDIS LWF using netcfg -u, i notice that it doesn't remove it from the driver store (can be seen with pnputil /enum-drivers).
This is causing problem because on some Windows 10 machines, if we uninstall the previous version of our NDIS LWF and install the new one using netcfg, for some unknown reason the old inf is still used to install it! And i assume its because the inf still has the same componentID? We are updating the INF file in order to attach to some virtual adapters that we previously couldn't attach. Note that this doesn't happen in Windows 7, and we can install the new one without any problem.
So my questions are:
Why is Windows still using the previous INF from driver store when we try to install the new updated driver that has a different INF?
What is the proper way to fully remove the previous NDIS LWF, including from driver store? If we need to use
pnputilto fully remove it from driver store, then what is the proper way of finding the OEM number, considering thatpnputil -drequires an OEM number?
Right, as you've noticed,
netcfg.exe -iis not the exact opposite ofnetcfg.exe -u.Installation does these steps:
Install the INF you provided with
-lto the driver store (SetupCopyOEMInf)Call
INetCfgClassSetup::Installto:-i(SetupDiBuildDriverInfoList,SetupDiSelectBestCompatDrv)AddReg,AddService, etc)Ndiregistry keyUninstall does these steps:
INetCfgComponent::DeInstallto:.Removesection of the INF (which, hopefully, contains aDelReg,DelServiceto undo everything done during install step #2.2)(The descriptions above ignore the driver refcount system (aka
OBO_TOKEN), since it isn't often used — most drivers just use a single refcount. If you exclusively usenetcfg.exeto manage your driver, then you too can ignore refcounts.)You might be wondering: why is this so very less-than-awesome? The backstory here is that
netcfg.exewas never really meant to be a general-purpose tool for 3rd party software to manage their drivers. It was only meant to be used internally, for the drivers that are built into the OS (ms_tcpipetc). The assumption was that 3rd party driver installers would want to call proper APIs likeINetCfg, notCreateProcesssome executable and screen-scrape the output. Sonetcfg.exewas only built up to be the minimum needed for our internal needs. In particular, very little attention was paid to uninstall, since built-in drivers are rarely uninstalled. (Likewise, argument parsing is inflexible, the help text is not helpful, and the error handling is not robust.)Starting in Windows 10, built-in drivers are no longer installed using
netcfg.exe, so the OS itself doesn't neednetcfg.exeat all anymore. But by then, 3rd party products had discovered it and taken a dependency on it, so we couldn't just removenetcfg.exeanymore. Ah well.This is a common gotcha. Note that, during install, steps #1 and #2 have no association between them. You could install a printer INF and a LWF at the same time —
netcfg.exe -l foo.inf -i barmakes no effort whatsoever to ensure that the "best" component selected in step #2.2 actually came from the INF installed in step #1.In order to ensure that the driver you want is the "best" driver, you have to ensure that your favored driver wins the PNP driver selection algorithm. I've personally been bitten by this because I didn't bump the
DriverVerline during development iterations. Make sure you incrementDriverVerevery time you change the driver.Honestly, if you want to do everything really correctly, I suggest avoiding
netcfg.exeentirely. Use the underlyingINetCfgAPIs instead. Then your installer will have to manage the driver (SetupCopyOEMInf/SetupUninstallOEMInf).You aren't losing much by ditching
netcfg.exeand callingINetCfgyourself.netcfg.exedoesn't do anything particularly fancy withINetCfg: its own implementation is nearly exactly taken from this sample code. If you start with that and slap a call toSetupCopyOEMInfon top, you'll pretty much be at parity withnetcfg.exealready. From there, you can improve it with more robust INF uninstall. You can even write some code to inventory all the INFs with your componentId, to make sure there aren't stale copies of your INF hiding around.You still have to make that leap of trust from installing an INF to hoping that
INetCfgClassSetup::Installthinks your recently-installed INF is the "best" INF. But if you've removed every other INF with that componentId, then you can be certain that the sole remaining INF must be the best match.