If your driver package includes drivers and INF files that replace "in-box" drivers and INF files, or if your package includes device-specific applications, it should include a device installation application that installs those components. The device installation application should be invoked by Autorun (described in Platform SDK documentation), so that it starts automatically when a user inserts your distribution disk.
Your driver package must handle two situations:
If the user plugs in new hardware before inserting your distribution medium into a drive, there are two scenarios to deal with:
In this case, Setup automatically installs the device based on INF files and drivers stored on the system disk. The system will not ask the user to insert vendor-supplied distribution media, so if you have provided a distribution medium containing device-specific applications, the applications are not installed at this time.
In this case the Found New Hardware wizard starts executing and asks the user for a distribution medium. When the user inserts the medium, the Autorun-invoked device installation application checks for in-progress installations. Because the Found New Hardware wizard is active, the device installation application should stop itself. The wizard can then search the medium for an appropriate INF file. You can provide a co-installer that installs device-specific applications, as described in Installing Device-Specific Applications.
In either of these cases, the system will also attempt to access the Windows Update Web site to see if newer drivers and INF files are available. If they are, these drivers and INFs will be used instead of those already on the system or on the distribution medium. If the Web site is inaccessible or if no new drivers are available there, the system uses the drivers and INFs available in-box or on the distribution medium (whichever are newer).
Your distribution medium can contain an Autorun-invoked device installation application. When the user inserts your distribution medium, this application will start automatically. Assuming the user inserts the medium after the device has been plugged in and installed, the device installation application can do either or both of the following:
If the user inserts your distribution medium before plugging in the hardware, an Autorun-invoked device installation application on the medium can:
Note that the behavior of an Autorun-invoked device installation application must depend on whether the user plugs in the hardware first or inserts the distribution medium first. Since vendors typically provide one distribution disk, and a disk can only have one Autorun-invoked application, your Autorun-invoked device installation application must determine if your device has been plugged in.
To determine if a device is plugged in, the application can call the UpdateDriverForPlugAndPlayDevices function, passing the hardware ID of the device. The device is plugged in if:
The device is not plugged in if the function returns FALSE and GetLastError returns NO_SUCH_DEVINST. (No installation occurs.)
When a device that formerly was attached has been unplugged, the device's devnode remains in the system, although it is both inactive and hidden. Before you can reinstall such a device, you must first find this "phantom" devnode, and mark it as needing reinstallation. Then, when the device is plugged back in, Plug and Play will reenumerate the device, find the new driver for it, and install the driver for the device.
To reinstall an unplugged device:
The SetupCopyOEMInf function ensures that the correct INF file is present in the %windir%\inf directory.
Call the SetupDiGetClassDevs function. In the call to this function, clear the DIGCF_PRESENT flag in the Flags parameter. You need to find all devices, not just those that are present. You can narrow the results of your search by specifying the particular device class in the ClassGuid parameter.
SetupDiGetClassDevs returns a handle to the device information set that contains all installed devices, whether plugged in or not, in the device class (assuming that you specified a device class in the first step). By making successive calls to the SetupDiEnumDeviceInfo function, you can use this handle to enumerate all of the devices in the device information set. Each call provides you with an SP_DEVINFO_DATA structure for the device. To get the list of hardware IDs, call the SetupDiGetDeviceRegistryProperty function with the Property parameter set to SPDRP_HARDWAREID. To get the list of the compatible IDs, call the same function, but with the Property parameter set to SPDRP_COMPATIBLEIDS. Both lists are MULTI-SZ strings.
Make sure that you perform full string comparisons between the hardware ID/compatible ID and the ID for your device. A partial comparison can lead to inappropriate matches.
When you find a match, call the CM_Get_DevNode_Status function, passing SP_DRVINFO_DATA.DevInst in the dnDevInst parameter. If this function returns CR_NO_SUCH_DEVINST, that confirms that the device is unattached (that is, has a phantom devnode).
Call the SetupDiGetDeviceRegistryProperty function with the Property parameter set to SPDRP_CONFIGFLAGS. When this function returns, the PropertyBuffer parameter points to the device's ConfigFlags value from the registry. Perform a bitwise OR of this value with CONFIGFLAG_REINSTALL (defined in regstr.h). After doing this, call the SetupDiSetDeviceRegistryProperty function, passing SPDRP_CONFIGFLAGS. This action modifies the registry's ConfigFlags value to incorporate the CONFIGFLAG_REINSTALL flag. This causes the device to be reinstalled the next time the device is reenumerated.
Plug and Play will reenumerate the device, find the new driver for it, and install that driver.
To preinstall driver files, your device installation application should follow these steps:
When the user plugs in the device, the PnP Manager recognizes the device, finds the INF file copied by SetupCopyOEMInf, and installs the drivers copied in Step 2. (For more information about copying INF files, see Copying INFs.)
If your distribution medium includes device-specific applications, the medium should include two methods for installing those applications:
If the user plugs in the device before inserting the distribution medium, and the device is not supported by in-box drivers, Setup calls the co-installer during the installation process. The co-installer should determine if the device-specific applications have already been installed and if they have not, it should install them. For more information, see Writing a Co-installer.
If the user inserts the distribution medium before plugging in the device, the medium's Autorun-invoked device installation application should determine if the device-specific applications have already been installed and if they have not, it should install them using Windows Installer. For more information, see the Platform SDK documentation.
If your device installation application will be invoked by Autorun when the installation CD is inserted, there is another consideration. If your application is meant for use on Windows 2000 and later (but not Windows 95/98/Me), it should determine if other installation activities are in progress before performing its installations. To make this determination, the application should call CMP_WaitNoPendingInstallEvents, typically with a zero time-out value. If the return value from this function indicates other installation activities are pending (for instance, the Found New Hardware wizard might be active), the device installation application should exit.
To make your device installation application compatible with platforms that don't support CMP_WaitNoPendingInstallEvents, the application should include the following code:
BOOL
IsDeviceInstallInProgress (VOID)
{
HMODULE hModule;
CMP_WAITNOPENDINGINSTALLEVENTS_PROC pCMP_WaitNoPendingInstallEvents;
hModule = GetModuleHandle(TEXT("setupapi.dll"));
if(!hModule)
{
// Should never happen since we're linked to SetupAPI, but...
return FALSE;
}
pCMP_WaitNoPendingInstallEvents =
(CMP_WAITNOPENDINGINSTALLEVENTS_PROC)GetProcAddress(hModule,
"CMP_WaitNoPendingInstallEvents");
if(!pCMP_WaitNoPendingInstallEvents)
{
// We're running on a release of the operating system that doesn't supply this function.
// Trust the operating system to suppress Autorun when appropriate.
return FALSE;
}
return (pCMP_WaitNoPendingInstallEvents(0) == WAIT_TIMEOUT);
}
int
__cdecl
_tmain(IN int argc, IN PTCHAR argv[])
{
if(IsDeviceInstallInProgress()) {
//
// We don't want to start right now. Instead, our
// device co-installer will invoke this application
// (if necessary) during finish-install processing.
//
return -1;
}
.
.
}
Use of this code is based on the premise that if a platform doesn't support CMP_WaitNoPendingInstallEvents, the platform does not invoke Autorun if installation activities are in progress. For a sample usage of this code, see the toaster installation package under the DDK's src/general subdirectory.
Device installation applications must do the following:
Device installation applications must not do the following: