After reading MSDN about device driver installation I have some general questions about the process. The question is not a question about a problem, but about the idea in general.
Hardware-first installation doesn’t look that complicated. Windows looks for preloaded drivers, then for preinstalled drivers, then dependently on settings and version tries to download drivers and install them silently.
Software-first installation looks a bit more complicated. Accordingly to these articles:
I have to call CMP_WaitNoPendingInstallEvents (if possible) to prevent interfering with possible started hardware-first installation.
The next step is to check if the device is plugged in. Here the 1st question arise. Why should I care about it? Is it another way to do CMP_WaitNoPendingInstallEvents’s job? Or something else?
And few other questions.
As I understand there is at least two layers of API: CM_ API, which is the lowest level API to interact with device tree and SetupDi which probably relies on CM_. The strange thing here is that there is no CM_ API function that creates a device node. devcon uses SetupDi(DIF_REGISTERDEVICE) to create a device node. Is it the only way to do it?
One more thing I don’t get is what code triggers creation of device node in the case of hardware-first installation? I suspect that co or class installer of bus driver does it, but really not sure.
And the last one: are co and class installers called only in the case of using SetupDi API? Or user mode component of PnP calls them in any case?
> After reading MSDN about device driver installation I have some general > questions about the process. The question is not a question about a > problem, but about the idea in general. >
I might not be an authority on the subject but I’ll try to help.
I understand this is done to prevent an unfavorable user experience scenario: user is already in progress of going through the Found New Hardware wizard. inserts the vendor’s CD, and then the vendor CD’s AutoRun kicks in and tries to install the driver in parallel.
> The next step is to check if the device is plugged in. Here the 1st > question arise. Why should I care about it? Is it another way to do > > > CMP_WaitNoPendingInstallEvents’s job?
No. Starting with the fact CMP_WaitNoPendingInstallEvents checks for any other driver installation process whatsoever, not specifically one for your device.
You do it to branch into three scenarios:
1. Your Hardware ID has non-phantom devnode(s) (i.e. plugged instances) This covers two cases: update an already-installed driver, and install a driver for a “question mark” device Course of action: UpdateDriverForPlugAndPlayDevices
2. Your Hardware ID has phantom devnode(s) (i.e unplugged instances) Course of action: Follow the recipe in “Determining Whether a Device Is Plugged In”
3. Your Hardware ID has no devnodes (i.e. was never plugged) Course of action: Preinstall the driver (so it’ll be available if the user ever decides to plug such a device)
> And few other questions. > As I understand there is at least two layers of API: CM_ API, which is the > lowest level API to interact with device tree and SetupDi which probably > relies on CM_. The strange thing here is that there is no CM_ API function > that creates a device node. devcon uses SetupDi(DIF_REGISTERDEVICE) to > create a device node. Is it the only way to do it? >
For PnP devices, you never create devnodes. For a newly-plugged device, the PnP Manager creates the devnode in kernel mode. then communicates it to a usermode service which launches SetupAPI – you can get a pretty good idea by watching SetupAPI.dev.log during device installation.
One more thing I don’t get is what code triggers creation of device node in > the case of hardware-first installation? I suspect that co or class > installer of bus driver does it, but really not sure. >
As I said, the PnP manager does it after enumerating the child devices of a bus driver.
Drivers themselves actually have no business dealing with devnodes at all. If you’re curious, there’s a pointer to the devnode somewhere in the undocumented portion of DEVICE_OBJECT (Windbg !devobj and !devnode would expose them to you).
And the last one: are co and class installers called only in the case of > using SetupDi API? Or user mode component of PnP calls them in any case? >
There’s plenty of use for SetupDi APIs – e.g. see devcon sample in the Windows DDK.
Also, a SetupDi API is used in every user app to find the device instance path when opening a device.
>user is already in progress of going through the Found New Hardware wizard.
AFAIR, Windows turns off autorun when starting Found New Hardware wizard. There is an option that a user runs installation by himself though.
Your Hardware ID has non-phantom devnode(s) (i.e. plugged instances)
This covers two cases: update an already-installed driver, and install
a driver for a “question mark” device
Course of action: UpdateDriverForPlugAndPlayDevices
But we already checked that no installation occurs with CMP_WaitNoPendingInstallEvents function. Why should we do it again?
???For PnP devices, you never create devnodes. For a newly-plugged device,
the PnP Manager creates the devnode in kernel ???mode. then communicates it
to a usermode service which launches SetupAPI – you can get a pretty good
idea by watching SetupAPI.dev.log during device installation.
Ah, so we need SetupDi(DIF_REGISTERDEVICE) only for non-PnP devices. Kernel PnP will create device node by itself.
???There’s plenty of use for SetupDi APIs – e.g. see devcon ??=8Bsample in the
Windows DDK.
I asked slightly different thing. It is not a problem to find examples of using SetupDi, but I would like to have a kind of general understanding of the process.
For now I know that user mode PnP (umpnpmgr.dll inside services.exe) interacts with kernel PnP through NtGetPlugPlayEvent and NtPlugPlayControl native APIs. You told me, that user mode PnP doesn’t create device nodes. As I understand user mode PnP exposes itself through CM_ API (RPC is used as transport). I thought that SetupDi is layered on top of CM_ API, so CM_ should have a function to create device nodes. (Though CM_ is implemented in SetupApi.dll nowdays).
Another question is if co-installers will be called in the case of using CM_ API. I just think that all these co/class installers scheme is implemented in SetupDi, not CM_, but not really sure.
Also, a SetupDi API??? is used in every user app to find the device instance
path when opening a device.
Didn’t get this sentence. Did you mean that SetupDi is involved in NtCreateFile?
> >1. Your Hardware ID has non-phantom devnode(s) (i.e. plugged instances) > > This covers two cases: update an already-installed driver, and install > >a driver for a “question mark” device > > Course of action: UpdateDriverForPlugAndPlayDevices > > But we already checked that no installation occurs with > > > CMP_WaitNoPendingInstallEvents function. Why should we do it again? >
CMP_WaitNoPendingInstallEvents checks no installation is currently in process.
I’m talking about determining the state in a completely idle system. The question:
For a given Hardware ID, does the system 1) have non-phantom devnodes, and 2) have phandom devnodes.
This has nothing to do with an in-progress driver installation, which might be an in-progress installation of a totally unrelated driver.
> For now I know that user mode PnP (umpnpmgr.dll inside services.exe) > interacts with kernel PnP through NtGetPlugPlayEvent and NtPlugPlayControl > native APIs. You told me, that user mode PnP doesn’t create device nodes. > As I understand user mode PnP exposes itself through CM_ API (RPC is used > as transport). I thought that SetupDi is layered on top of CM_ API, so CM_ > should have a function to create device nodes. (Though CM_ is implemented > in SetupApi.dll nowdays). >
That sounds legit, but to be sure, I’d read one of the NT Internals books on the subject, probably written by someone with source access
> Another question is if co-installers will be called in the case of using > CM_ API. I just think that all these co/class installers scheme is > implemented in SetupDi, not CM_, but not really sure. >
I’m not really versed in this, but looking at the PnP Configuration Manager API, I see nothing to do with installing INFs at all, so I suspect CoInstallers belong to a higher API level (e.g. the device installation API).
> >Also, a SetupDi API??? is used in every user app to find the device > instance > >path when opening a device. > > Didn’t get this sentence. Did you mean that SetupDi is involved in > NtCreateFile? >
>CMP_WaitNoPendingInstallEvents checks no installation is currently in
process.
Ok.
I’m talking about determining the state in a completely idle system. The question:
For a given Hardware ID, does the system 1) have non-phantom devnodes, and 2) have phandom devnodes.
This has nothing to do with an in-progress driver installation, which might be an in-progress installation of a totally unrelated driver.
Well, it looks I’ve got how it works. The doc is a bit vague about it. If UpdateDriverForPlugAndPlayDevices returns true, then I have to stop installation – it is already in progress. No need to preinstall the driver, it is already done by UpdateDriverForPlugAndPlayDevices.
Interesting thing what happens if UpdateDriverForPlugAndPlayDevices returns false, we check phantom nodes, call preinstallation and sly user inserts the device?
???I’m not really versed??? in this, but looking at the PnP Configuration Manager API, I see nothing to do with installing INFs at all, so I suspect CoInstallers belong to a higher API level (e.g. the device installation API).
The point here is to know if ejecting device using CM_ notifies co-installers.
> Interesting thing what happens if UpdateDriverForPlugAndPlayDevices > returns false, we check phantom nodes, call preinstallation and sly user > inserts the device? >
I don’t think CMP_WaitNoPendingInstallEvents is intended for locking, otherwise it’d be an acquire-release-lock API It’s merely offered to avoid confusing user experiences, not to ensure security or integrity. You’re taking it for more than it is.
For example, in my apps, I use CMP_WaitNoPendingInstallEvents to wait for driver installations to “settle down”. For example, say I’m waiting for a USB disk drive to be plugged, so I RegisterDeviceNotification (for GUID_DEVINTERFACE_USB_DEVICE) and wait for a WM_DEVICECHANGE. When plugged, I receive notification (about the USB Mass Storage device) but I know more is coming (the volume child devices are being enumerated) so I do CMP_WaitNoPendingInstallEvents instead of probing the newly added volumes as they come (which is, too, an option).
> The point here is to know if ejecting device using CM_ notifies > co-installers. >
Since MSDN discourages you whenever possible from using CM in lieu of SetupDi, you’d think SetupDi provides co-installer support and CM skips it, right? However, I cannot find any such claim in the MSDN.
>???I don’t think ???CMP_WaitNoPendingInstallEvents is intended for locking,
otherwise it’d be an acquire-release-lock API It’s merely offered to
avoid confusing user experiences, not to ensure security or integrity.
You’re taking it for more than it is.
Well, I suspect it. I just try to understand why should I call this function. What will happen if I will not do it? For sure a lot of questions like this have a very short answer: “Just because you have to”. But it always interesting to understand what’s going on inside.
Since MSDN discourages you whenever possible from using CM in lieu of
SetupDi, you’d think SetupDi provides co-installer support and CM skips it,
right? However, I cannot find any such claim in the MSDN.
Exactly. I didn’t find anything about it in MSDN too. It just an assumption. Don’t know why does MS discourage CM_ – for some serious reasons like missing calls to co/class installers or just for great justice.
I also have feeling that CM_ appeared earlier than SetupDi. And then SetupDi was layered above CM_. cfgmgr32.dll just forwards all exports to SetupDi.dll now. But if so, there must be CM_ call for creation of device node, like SetipDi(DIF_REGISTERDEVICE) does. It couldn’t be removed because of backward compatibility.
I also have feeling that CM_ appeared earlier than SetupDi. And then SetupDi was layered above CM_. cfgmgr32.dll just forwards all exports to SetupDi.dll now. But if so, there must be CM_ call for creation of device node, like SetipDi(DIF_REGISTERDEVICE) does. It couldn’t be removed because of backward compatibility.
Absolutely correct. The CM_ functions arrived with the introduction of
plug-and-play in Windows 95 and are common across all of the systems.
The SetupDi functions arrived in Windows 2000 and are NT-only.
–
Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.
Well, quick disassembly of SetupDiCallClassInstaller (and the name of the function) shows that co installers are called by SetupDiCallClassInstaller. I also found CM_ for device node creation, though it is not documented for now days.
From WinDDK\7600.16385.1\src\setup\devcon\cmds.cpp:
/*
…
Callback for use by Enable/Disable/Restart
Invokes DIF_PROPERTYCHANGE with correct parameters
uses SetupDiCallClassInstaller so cannot be done for remote devices
Don’t use CM_xxx API’s, they bypass class/co-installers and this is bad.
…
*/