Win32 Application Support for Plug and Play

Lee Fisher

January 18, 1995

Abstract

This article gives an overview of Plug and Play from the Win32® application programmer's perspective. It discusses the current implementation for Microsoft® Windows® 95, and gives an overview of what is required by Win32 applications in order to work best in an operating system that provides this functionality. In many cases, it is important for an application to realize what hardware changes are occurring underneath it—failure to do so may result in lost data or your application crashing. Understanding how the operating system works at the hardware level, and having the application plugged into relevant notifications of these changes, means an application can avoid crashes, add additional functionality, and make itself easier to use.

What Is Plug and Play?

One of the main innovations in Microsoft® Windows® 95 is "Plug and Play" support. Plug and Play is the name of an ambitious, open, industry-standard technology that lets PC hardware and attached devices work together automatically. A user can simply attach a new device ("plug it in") and begin working ("begin playing"). This should be possible even while the computer is running, without restarting it.

Plug and Play is implemented at all levels. At the hardware level, systems with a Plug and Play–compatible BIOS will recognize Plug and Play hardware in the system and will cooperate with an aware operating system to make the hardware work optimally. Still at the hardware level, adapters and peripherals support Plug and Play. Most new interfaces such as PCI and PCMCIA already have Plug and Play support. The main older interface, ISA, has been updated to be ISA Plug and Play, so that dip switches and jumpers will no longer be needed, while still being compatible with a large market of older systems that use this bus. At the software level, the Windows 95 operating system is fully Plug-and-Play capable. Finally, still at the software level, are all the other applications in the world. They can continue to be ignorant of the hardware happenings around them, or they can use this new Plug and Play interface and have fewer problems and make things easier for the end user.

With Plug and Play technology, users can easily add new capabilities to their PCs, such as sound or fax, without having to concern themselves with technical details or encountering problems. For users of mobile PCs (who are frequently changing their configurations with docking stations, intermittent network connections, and so on), Plug and Play technology will easily manage their changing hardware configurations. For all users, Plug and Play will reduce the time wasted on technical problems and increase productivity and satisfaction with PCs.

There are a variety of Plug and Play technologies, including BIOS (system boards), ISA, PCMCIA, PCI, SCSI, IDE CD-ROM, MicroChannel, and so on. For most of the specific bus/port hardware interfaces, a specification is available. In a nutshell, at the hardware level, each device must be able to be uniquely differentiated from other peer devices—the device must state the services it provides and the resources it requires, it must identify the driver that supports it, and it must allow software to configure it. The main resources involved are interrupts, I/O ports, DMA channel, and memory ranges. For the ISA bus, configuring these resources has traditionally required various dip switches, jumpers, specialized configuration utilities, and heavy interaction with the technical support groups of the makers of the hardware, the system, and the operating system.

In general, there are a few kinds of dynamic hardware protocols: cold, warm, and hot. Cold means that hardware can only be inserted or removed (or "plugged" and "unplugged") while the computer is turned off. Warm means that the main system can remain on, but most of the software (including the operating system and all of the applications) must be closed. (In a portable computer with a docking station, “warm docking” means the computer needs to be suspended for the docking action to take place. When the system is resumed from this suspended state, the system will reenumerate hardware now present.) The warm case is the most interesting case to ISVs, because this is when hardware can be added or removed while the system is up and running, and all hardware and software is expected to handle this hardware change properly.

However, applications are mainly interested in "hot" hardware (system remains on, software can stay open). At first glance, this might only appear to be the PCMCIA card. However, these days PCMCIA adapters span most of the entire hardware range, so if there's hardware you care about watching, it is most likely available for the PCMCIA bus. In any case, ALL hardware—even old ISA bus adapters—can be affected: a portable can dock or undock from its docking station, and any combination of hardware can exist on the docking station, which might come or go at any time to applications. So, hot-pluggable buses got things started, but docking stations generalized the issue across the range of buses.

Why Should Applications Be Concerned?

Traditionally, there have been a few areas where applications have been aware of hardware. Normally such awareness has been of a static nature—that is, applications observe the value of error codes returned by operating system functions. Sometimes the hardware was watched continuously for changes, such as when printing or waiting for a UPS to go off during a power failure. However, there have been few cases where the application interface allowed the hardware to inform applications of changes—where applications have been able to be dynamically aware of the status of hardware. The signal() function notified applications of simple program interrupts and serious system stability problems. Some Windows system messages announced changes in some GUI characteristics. Some return codes from operating system functions often signified hardware status. Many kinds of hardware have offered insight into their status, but normally only via proprietary IOCTL interfaces. The Plug and Play interface solves this, providing a detailed level of information from all forms of hardware when anything changes.

Windows 95 Enhancements

With Windows 95, the system is made easier to use by watching for Plug and Play messages from hardware and drivers, and doing intuitive things for the user. When new hardware is installed into the system, the Plug and Play protocols work with the new hardware, the BIOS, and the operating system to identify and allocate the necessary resources, activate the new hardware, and load the appropriate driver. If the driver is not already present in the system, the operating system will ask the user for a disk with this driver.

When a user installs a CD-ROM drive to the system, the operating system automatically detects a new SCSI device, loads the relevant drivers, and adds a new drive letter, which would then appear on the desktop. When a user installs a new printer—or any kind of Plug and Play peripheral attached to a Plug and Play adapter—similar intuitive results occur, making the system much easier to use.

Another example of this is a new Windows 95 user feature called "AutoPlay." When a new disc is inserted into a drive, the operating system recognizes this and runs a batch file. It is fairly obvious that when users insert a disc into the drive, they want to use it. Now users won't have to identify the appropriate application to execute and explicitly run it. Instead, AutoPlay-enabled applications can automatically start themselves. Or, if this is the first run, the first floppy disk or the CD-ROM disc can automatically begin setup. AutoPlay is just one example of how Windows 95 is making use of the power of Plug and Play for everyday tasks.

Windows 95 contains a major new system component called the Configuration Manager, which orchestrates Plug and Play activity from the hardware, the BIOS, and the rest of the operating system. There are many members of this Plug and Play "symphony." The systemboard BIOS has a driver that talks to the operating system. For each bus in the system (PCMCIA, PCI, and so on), there is a bus "enumerator" driver, which is responsible for unique identification of each device on that bus and determining the resource requirements of each device. For each managed resource in the system there is an "arbitrator" driver, which decides what resources go to a device when two or more devices request the same resource (such as the same hardware interrupt). Lastly, there are the device drivers for each device in the system.

Each time the system is started, the Configuration Manager works with the BIOS and bus drivers to find a workable hardware resource configuration in which all hardware can be loaded, the hardware is activated, and the relevant device drivers are loaded. The same procedure happens when new hardware is detected; in addition the Configuration Manager also works with Setup to find the relevant device driver(s) to load, if they aren’t already present in the system.

For older, non-Plug and Play “Legacy” hardware, the operating system obviously cannot use most of these new hardware protocols. Information on this static hardware is determined by Setup and by the user (aided by information in .INF files provided by the hardware vendors), and stored in the system’s Registry. During startup, the Configuration Manager first looks at the static hardware resource requirements of any present legacy hardware, then works around these requirements when dealing with the Plug and Play hardware.

Application Effects Caused by Hardware

Application programmers need not worry about almost all of the lower-level details of the Plug and Play hardware, BIOS, driver, and operating system protocols. Most of that is the responsibility of the IHV, the OEM, and the operating system maker. Actually, ISVs won’t even be able to see many of the Plug and Play protocol issues that occur during system startup (before applications are run) and shutdown (after all applications have been terminated).

But while applications are running, when hot-pluggable hardware is present—which can be any hardware when a docking station is involved—there are many activities that might occur that will affect applications.

In whatever way your application relies on hardware or software only available via some hardware bridge (such as a network), your code should be dynamic enough to handle these changes (to take advantage of new hardware when it is added, to properly recalculate information for hardware that changes, and to gracefully recover when hardware is removed).

Hopefully you should now have some idea of the nature of the problem that Plug and Play solves at the hardware level, and some of the implications at the application level, and also a desire to add appropriate support in your application to be aware of the relevant set of Plug and Play information.

Luckily, implementing Plug and Play support is not too hard. As a developer for Windows, you should be aware of the system messages defined in the Win32® API. Adding Plug and Play support is basically a matter of watching a few new messages! And even the logic of these messages should be familiar, because the system shutdown messages follow a similar model.

The WM_DEVICECHANGE Device Change Message

The main Win32 interface to Plug and Play is via a new message, WM_DEVICECHANGE, available as an ID under WM_COMMAND. This new Device Change Message has various event codes that give more details about change in the device, if it is being added, if it is about to be removed, it if was just removed, and so on.

In the main window procedure, use switch statements similar to the ones below to obtain information on the Plug and Play Device Change Message and its parameters.

    LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM uParam,
                              LPARAM lParam)
    {
        int wmId, wmEvent;
        /* ... other procedure initialization overhead ... */
    
        switch (message) { 
    
            case WM_COMMAND:
                wmId    = LOWORD(uParam);
                wmEvent = HIWORD(uParam);
    
                switch (wmId) {
    
                    case WM_DEVICECHANGE:
                         /* ... Plug and Play specifics here! ... */
                        break;
     /* ... rest of message handling window procedure ... */

At this point, the event code points to one of various DBT_* event codes that contain different kinds of information. The Windows 95 Software Development Kit’s DBT.H header file goes into good detail on these messages, the main ones of which are summarized below.

The DBT_DEVTYP_* Event Codes

Before going on to describe the main DBT_* event codes, it is useful to understand the kinds of devices that these messages can represent. The main DBT_* event codes carry information as to the type of hardware, contained in the DBT_DEVTYP_* values. The lParam points to the PDEV_BROADCAST_HDR structure, and this structure’s dbch_devicetype field contains this information. For example:

((PDEV_BROADCAST_HDR)lParam)->dbch_devicetype)

Values of DBT_DEVTYP_* values are:

DBT_DEVTYP_OEM OEM-defined device type
DBT_DEVTYP_DEVNODE devnode number (specific to Windows 95)
DBT_DEVTYP_VOLUME logical volume (drive)
DBT_DEVTYP_PORT serial or parallel port
DBT_DEVTYP_NET network resource (UNC)

Of these device type values, DBT_DEVTYP_VOLUME is arguably the most useful: It shows when a drive letter (local or remote) is coming or going. The DBT_DEVTYP_DEVNODE is specific to Windows 95, and would not be available in Windows NT.

DBT_* Event Codes

The main activities that are tracked with the WM_DEVICECHANGE message and the DBT_* event codes occur when new hardware is added; there is also a series of event codes for when existing hardware is removed.

Most of the main DBT_* messages pass a pointer to a structure. These structures are named _DEV_BROADCAST_* and are also defined in DBT.H, as in the PDEV_BROADCAST_HDR example above. These structures normally contain the size of the device (meaning specific to a particular kind of medium), a name or identifier, and a flag word. There is a structure for each kind of DBT_DEVTYP_* value.

Those are the main DBT_* event codes. Some of the remaining—lesser used—ones are included here for more background.

There are a handful of DBT_* event codes for specific communications with the Configuration Manager. Some of these are used by ring 3 (user-mode) applications communicating with this VxD via BroadcastSystemMessage(). Others are used by ring 0 (kernel-mode) VxDs who also watch these Plug and Play messages and have more relevance to drivers than to applications. Such messages include the following:

The DBT_SHELLLOGGEDON event code is used by VxDs who need to know when the Shell has finished logging on, signifying that VxDs are able to perform more functionality in the system, such as executing applications.

The DBT_VOLLOCK* series of event codes (QUERYLOCK, LOCKTAKEN, LOCKFAILED, QUERYUNLOCK, LOCKRELEASED, and UNLOCKFAILED) all deal with Exclusive Volume Locking, a feature of Windows 95 to allow applications to lock a disk even though open files exist. For more information on this feature, see the Windows 95 IFS Manager and I/O Supervisor documentation.

The DBT_NO_DISK_SPACE event code is issued by the IFS Manager when it detects a drive that has run out of free space. The lParam contains the 1-based drive number.

Lastly, this applications/hardware communications method does provide a means for proprietary communications to hardware. The DBT_USERDEFINED event code is a general-purpose interface, rather like an IOCTL.

The WM_DISPLAYCHANGE Display Change Message

If the WM_DEVICECHANGE is the “main” Plug and Play message, another, less overloaded message is the WM_DISPLAYCHANGE message. This message only tracks changes in display mode. If the mode changes, applications that are dependent on this might need to compensate.

The message parameters contain information about the new display mode. The wParam for the message contains the new display color depth and the new pixel resolution is packed in lParam. Since this message arrives asynchronously, an application that depends on the display resolution or color depth should use standard means to determine the current settings instead of relying on the message parameters. This is required because the display mode can change multiple times before an application processes the first WM_DISPLAYCHANGE message. For example:

case WM_DISPLAYCHANGE: {
    HDC hdcScreen = GetDC(NULL);
    UINT uBPP = GetDeviceCaps(hdcScreen, PLANES) *
        GetDeviceCaps(hdcScreen, BITSPIXEL);
    SIZE sRes = {GetSystemMetrics(SM_CXSCREEN),
        GetSystemMetrics(SM_CYSCREEN)};
    ReleaseDC(NULL, hdcScreen);
    //
    // do stuff with new info...
    //
    break;
}

Note   At present, Windows does not change the display color depth on the fly. In near-term future releases of Windows, color depth may indeed change on the fly, and the system will automatically convert any GDI objects the application owns for the new color depth. Thus, most applications will not require extensive special processing of this case unless they are highly dependent on the formats of device bitmaps. Typically, applications only need to update any global variables where such information is cached.

Power Management

A technology very closely related to Plug and Play is Power Management, also known as Advanced Power Management (APM). Windows 95 supports APM version 1.1, a vast improvement over the 1.0 support in MS-DOS® and Windows 3.x.

Power Management is concerned with the state of the system power usage. The application interface of Power Management is very similar to Plug and Play. Instead of WM_DEVICEBROADCAST, the message to watch is WM_POWERBROADCAST.

Instead of the DBT_ Device Broadcast Type messages, Power Management has the PBT_* Power Broadcast Type messages, available as event codes in WM_POWERBROADCAST’s uParam. And similar to DBT_* messages being documented in the SDK’s DBT.H, the PBT_* messages are documented in the SDK’s PBT.H.

There are a set of messages for Suspend mode. Suspend mode is when the system is not working, the CPU clock is stopped, most power-managed devices are not powered, and the system may take a relatively long time to return from this Suspend mode to the normal Enabled mode. The PBT_APMQUERYSUSPEND message is sent when the system is asking if it is safe to switch to Suspend mode. If available, applications can perform user interactions to clean up (save files, and so on) before they are about to go into this mode, or attempt to veto this mode switch. If no user interaction is allowed, applications will have to programmatically determine if the mode switch is safe at this time. If someone determines it is unsafe to switch into Suspend mode, the PBT_APMQUERYSUSPENDFAILED message is sent, and applications may resume normal operations. To summarize: The PBT_APMSUSPEND message is sent immediately before the system is about to go into Suspend mode; the PBT_APMRESUMESUSPEND message is sent when the system comes out of Suspend mode, and applications may again resume normal operations.

Standby mode is when the system may not be working, the CPU clock may be stopped, most devices are in a low power mode, and the system can return quickly from this Standby mode to the normal Enabled mode. There is a set of PBT_STANDBY messages of the same format as the above SUSPEND messages. However, unlike Suspend mode, these Standby mode messages are sent to applications as well as device drivers.

The PBT_APMPOWERSTATUSCHANGE message is sent when there is a change in the power status of the machine, such as battery power running low, switching power from battery to A/C, battery charge completion, and so on. Upon receiving this message, applications interested in this sort of information should look at the details in the PBT_PowerStatusChange lParam for more information. Some applications might want to go on to call the Win32 API GetSystemPowerStatus() for more details; note that this API is currently only available on Windows 95. Watching for the system switching to battery power is a good time to reduce an application’s tasks, to use less power while the system is running on battery power.

The PBT_APMBATTERYLOW message is sent when the power supply is running low. This is a good time to flush dirty buffers to disk, and to cut down on unnecessary “background” operations that would cause additional drain on the battery.

The PBT_APMRESUMECRITICAL message is sent upon return from a BIOS Critical Power, a drastic case such as a failing battery. Before a BIOS Critical Suspend occurs, there is no time for device drivers or applications to be warned, so when the system is running again after this message is sent, applications should do their best to restore themselves.

The PBT_APMOEMEVENT message is a mechanism to allow for OEM-specific power messages.

Putting It All Together

Armed with messages such as WM_DEVICECHANGE, WM_POWERBROADCAST, and WM_DISPLAYCHANGE, and all of their DBT_* and PBT_* messages, an application will have the fundamental system awareness necessary to make intelligent decisions about device usage in a dynamic hardware environment. However, there are a few things you must do in your application in order to take advantage of the additional awareness provided by these Win32 Plug and Play messages. You need to determine how to use them properly—when to pay attention to this information and when to ignore it.

It is relatively simple to watch for system messages to find out when a disk is going away. You now need to find out what disk it is, if you have any files on that disk, if these files were opened with write access, if these files have unflushed data buffers. Then and only then do you need to take action and save your data, by automatically saving the data, or by asking the user if he or she wishes the data saved or might rather wish to cancel this ill-timed disk removal sequence.

In such a case, it is useful to have a Boolean variable for each file opened with write access that tracks the state of the file’s data buffers (written to disk or not). The variable would be set when the buffers became dirty, checked when deciding to save the data or if a disk remove message occurs, and cleared when the data is saved.

Available Platforms

Plug and Play support is available in the Win32 API, not in the older 16-bit Windows or MS-DOS interfaces. Plug and Play application support is available on the Windows 95 operating system, not older versions of MS-DOS or Windows 3.x, even with Win32s®. (Actually, Intel does produce software to give MS-DOS and Windows 3.x some Plug and Play support, but this is primarily for device drivers to manage resources; there are no application-level Plug and Play messages.)

The next major release of Windows NT will include full Plug and Play support in the next generation of Windows NT (nicknamed “Cairo”). The Plug and Play device driver architecture will be different, because the Windows 95 and Windows NT device driver architectures are very different. However, the Win32 interface to Plug and Play should be similar, perhaps with some differences in semantics.

A Win32 application can add support for these Plug and Play messages and test them on Windows 95. It is valid to have this message-handling code in code bases that are run on other current Win32 platforms (Win32s, Windows NT 3.x): only on Windows 95 will they currently be called. When Windows NT “Cairo” adds support, the semantics may have changed a bit, so it would be useful to put assertions in the code to run through these code paths carefully when this new Plug and Play Win32 environment is available.

More Information

The Windows 95 Software Development Kit (SDK) contains information on the Win32 API. The final Windows 95 SDK will contain more information on the Win32 interface to Plug and Play.

In addition to the Win32 API documentation in the SDK, it is useful to read some of the lower-level hardware documentation. Although a comprehensive knowledge of the many hardware protocols and device driver interfaces is not necessary to write proper Win32 applications, a basic understanding of these protocols and interfaces will provide insight to what is happening under the covers—in the hardware, BIOS, device drivers, operating system, and eventually, to the applications. Armed with this additional background, you will be able to better understand the Plug and Play messages you’ll receive in your message queue, and what kind of messages you should be watching for.

The Windows 95 Device Driver Kit (DDK) contains information on the general system device driver interface (VxD), as well as the various media-specific driver interfaces.

The Plug and Play specifications—operating system–independent, not specific to Windows 95—show how to design Plug and Play hardware that will work with any Plug and Play operating system. The main place to obtain these specifications is on CompuServe® in the Plug and Play (GO PLUGPLAY) forum libraries. In addition, this forum’s message base is the primarily location of industry-wide discussions, dialogs, and support about Plug and Play. The specifications are also available on the Internet in ftp://ftp.microsoft.com/developr/drg/Plug-and-Play/.

The book Hardware Design Guide for Microsoft Windows 95, (Redmond, WA: Microsoft Press, ISBN 1-55615-642-1, 1995) is a guide for OEMs and IHVs to explain the “PC 95” hardware platform, and to show how to develop Plug and Play hardware to fit this new generation of hardware definition.

The Plug and Play Association was created to guide the industry future of Plug and Play. Co-chaired by Microsoft and Intel, with core committee members of 3Com, Compaq, IBM, Intel, Microsoft, and National Semiconductor. Membership is open to the microcomputer industry. For more information, contact them at:

Plug and Play Association
P.O. Box 14070
Portland, OR 97214-9499, USA
Phone: (800) 433-3695 (US/Canada)
Phone: (503) 797-4244 (International)
Fax: (503) 234-6762

The Microsoft Plug and Play Hardware Catalog is a showcase for Plug and Play products. Current issues are on the previously listed CompuServe and Internet FTP locations. Included in the catalog is information on how to submit new entries for subsequent issues.

Microsoft also has a technical marketing mailing list for vendors interesting in Plug and Play, members of which will receive announcements of new specifications, related events (such as WinHEC), and other related information and industry events. To get on this marketing mailing list, e-mail playlist@microsoft.com.

Summary

In summary, some classes of applications will benefit from the ability to determine when hardware resources are added or removed from the system, when the power supply switches to/from battery, and when the battery power supply is running low. Watching these WM_DEVICEBROADCAST, WM_POWERBROADCAST, DBT_*, and PBT_* messages and reacting properly (saving data if the data store is going away, reducing activity when power is getting low, adding new functionality or doing intuitive things when new resources are made available) will make your application work better in a dynamic hardware environment.

Plug and Play is a useful new feature for personal computer hardware and operating systems. However, this protocol is only as strong as the weakest link in the system. The user will benefit the most with a machine for which an OEM has provided BIOS support, using adapters and peripherals for which IHVs have provided hardware support, and using software for which ISVs have provided application support. If you make the few necessary changes, your application will not be the weakest link in the chain.