Why Do We Need WDF Coinstallers?

Lately, I've been hearing lots of questions like "why do we need this bloated KMDF/UMDF coinstaller?" or "why don't you use an msi" or "why doesn't a WDM driver always need a coinstaller?", etc both in some mailing lists and in emails. So, I'd like to throw some light into this issue.

First of all, I'd like to say that the coinstaller is actually doing 2 very important tasks:

  • Update the framework of the computer (i.e. that files that are on the disk), if necessary (i.e. if the coinstaller supports KMDF 1.7 and the computer has KMDF 1.5, then there will be an update, however if the coinstaller supports KMDF 1.5 and the computer has KMDF 1.7, then there is no reason for update)
  • Configure the device node, after the driver files are copied to the disk

 
QUESTION 1: Why are the coinstallers so big?  

If you take a look at the WDF coinstallers, their size for x86 architectures are ~1mb. This gives a false impression that they are bloated. However, more than 99% of the size is attributed to the "update" part (1st bullet) and only a few kb are responsible for the "configure" part (2nd bullet). Let's see why this happens.

KMDF 1.7 currently supports all OSs from Windows 2k to Windows Vista SP1 (both client and client and server). UMDF 1.7 currently supports all OSs from Windows XP to Windows Vista SP1 (both client and client and server). This means that if you write your driver with UMDF/KMDF 1.7, then the same binary will work for any OS in that range. Let me repeat that: we ensure both source-code compatibility, as well as binary compatibility for all the above-mentioned operating systems! Currently, you CANNOT do this with any other driver model for Windows. If you write a WDM driver that works in Vista and takes advantage of the latest WDM features, this driver won't work in 2k. However, if you write a WDF 1.7 driver, then it will.

In order to do this, we have to update the operating system that you're installing the driver at. This is done by the coinstaller. The coinstaller has an embedded Windows Update packages inside it that is actually executed in the beginning of the installation, if it's needed. This package includes the latest version of the WDF files that correspond to the current coinstaller. So,  in the case of the KMDF 1.7 coinstaller (wdfcoinstaller01007.dll) , we update wdfldr.sys and wdf01000.sys, which are located at %windir%\system32\drivers. The UMDF 1.7 coinstaller (WUDFUpdate_01007.dll) updates wudfhost.exe, wudfplatform.dll, wudfsvc.dll, wudfx.dll and wudfcoinstaller.dll (located at %windir%\system32), wudfpf.sys, wudfrd.sys (located at %windir%\system32\drivers). Currently, each coinstaller has 2 Windows Update packages: 1 for pre-Vista operating systems (e.g. 2000, XP, 2003, etc) and 1 for Vista (RTM, SP1). This happens, because the windows update technology changed in Vista. These 2 packages combined are around 99% of the coinstaller size. The other 1% is just the code for the configuration of the device and is pretty minimal (a few kb only).

So, if we didn't update the system, then our coinstallers would be really small. However, in that case it would not be possible for driver developers to write drivers that are source code compatible and binary compatible back to Windows 2000. WDM doesn't have full backwards binary compatibility.

QUESTION 2: How can you verify that what I'm saying is correct?

This is easy. Let's take a look at the KMDF 1.7 x86 coinstaller. Its size is 1098kb. Now, let's look at the KMDF files. wdf01000.sys is 492kb and wdfldr.sys is 35kb. Their sum is 492+35=527kb. I already said that we have 2 update packages in each coinstaller, so this size is multiplied by 2 and becomes 527*2=1054kb. Of course, each update package has additional files that are needed by Windows Update and everything is compressed, however you get the general idea. The same thing applies for the UMDF coinstaller, too.

However, if you want to delve deep into the coinstaller's contents, then you just need to disassemble the coinstaller and look at the files inside it. Bob has already written a post about how to do it here, but I'll repeat the steps for completeness:

  • Drag-and-drop the coinstallers into Visual Studio or use File/Open to load the binary. You can also use any other resource extractor.
  • By default, you'll see the coinstallers' resources. Look at the RCDATA resources. The KMDF coinstaller has a resource called WDFCAB_RESOURCE and the UMDF coinstaller has 2 resources: WUDF_UPDATE_VISTA_RTM (Vista update package) and WUDF_UPDATE_XP-SRV03 (XP and 2003 update package).
  • Right click on the resource name, select export and find a directory to extract the resources.
  • For KMDF, the filename needs to have a .cab extension. For KMDF, the pre-Vista update file needs to have a .exe extension, while the Vista one needs to have a .msu extension.
  • If you uncompress the .cab KMDF file somewhere, you'll see a file called Microsoft Kernel-Mode Driver Framework Install-v1.7-Win2k-WinXP-Win2k3.exe (pre-Vista update package) and a file called (Microsoft Kernel-Mode Driver Framework Install-v1.7-Vista.msu).
  • You can open the exe and the msus using a program that zips/unzips compressed files (like WinZIP, WinRAR, etc), or you can execute the KMDF exe with the  "/extract:<directory_to_extract_files> /quiet" arguments and extract the files.

 After that you can look at the file sizes, extract them from the coinstaller and see how big the coinstallers really are.

QUESTION 3: Why not use an msi?

As you know, there are 2 ways to install a device and its driver:

  • Hardware-first: Plug-in the device, point the "add-new hardware wizard" to
    the inf and install the driver
  • Software-first: Install the driver, then plug-in the device

In KMDF and UMDF we want to provide support for both ways and we don't want to
change the model that windows drivers have been using so far. This means that we
need an inf to install the driver. If we provided just an msi, which you'd have
to install before pluging-in your device, this means that we're breaking the
hardware-first installation. We don't want to do that, that's why we have the
coinstaller

So, the inf calls the coinstaller, which includes a windows update package. This
package updates the WDF binaries that are on disk. From the user's perspective,
it doesn't have any difference, if the coinstaller is internally using an msi, a
windows update package or any other technology. So, just by replacing the update
technology and using an msi, wouldn't give any benefit. On the contrary, we'd
have to start development and testing from scratch and find solutions to
problems like how it's possible to overcome Secure File Protection in Windows
Vista in such a way that we don't break support for Windows 2000. At the same
time, we also need to keep our binary small. That's why we're not changing the
current architecture (at least until we find something better).

QUESTION 4: Why not use a different update mechanism?

Some alternatives here would be to put the Windows Update package in Windows Update (e.g. the same way that it works with applications that depend on DirectX and .NET). For example, we could have a small coinstaller that checks the UMDF/KMDF version that's installed in the system and then asks the user to download the package. The problem here is that this solution works well with APPLICATIONS, but not with DRIVERS. It's acceptable, that if you try to install a .NET 3.5 application, and you have .NET 2.0 installed in the system, then this case you'll have to connect to the internet, download .NET 3.5, install it and run the application. However, what happens, if you have KMDF 1.5 in the system and your brand new keyboard/mouse need KMDF 1.7? How do you control the computer then? Or how do you connect to the network, if the device that needs KMDF 1.7 is your network card? What if you have no internet connection at all and you want to use your brand-new cool gadget that is supported by a UMDF version that's newer than the one already installed in the system? So, this solution cannot work.

 

Summarizing, we need WDF coinstallers, because:

  • We want both to update the framework (in all supported operating systems) and configure the device
  • We need something that can be called from the inf, so that we don't break the driver installation methods and patterns
  • We need to install DRIVERS and not APPLICATIONS