Defining a Device Class

[Previous] [Next]

Let's suppose you have a device that doesn't fit into one of the device classes Microsoft has already defined. When you're initially testing your device and your driver, you can get away with using the Unknown class in your INF file. Production devices are not supposed to be in the Unknown class, however. You should instead place your custom device into a new device class that you define in the INF file. I'll explain how to create a custom class in this section.

The INF example I showed you earlier relied on a custom device class:

[Version] Signature=$CHICAGO$ Class=Sample ClassGuid={894A7460-A033-11d2-821E-444553540000}

In fact, all of the samples in this book use the Sample class.

When you want to define a new class of device, you only need to do one task: run GUIDGEN to create a unique GUID for the class. You can add polish to the user interface for your device class by doing some additional tasks, such as writing a property page provider for use with the Device Manager and putting some special entries into the registry key your class uses. You can also provide filter drivers and parameter overrides that will be used for every device of your class. You control each of these additional features by statements in your INF file. For example:

[ClassInstall32] AddReg=SamclassAddReg CopyFiles=SamclassCopyFiles [SamclassAddReg] HKR,,,,"WDM Book Sample" ... [SamclassCopyFiles] ...

The illustrated registry entry turns into the "friendly name" for the device class in the Device Manager and in the list of device types displayed by the add hardware wizard. I'll explain some of the additional registry entries you might want to add to the class key in the following sections.

NOTE
None of my INF files has a ClassInstall32 section. None is needed because the setup program for the sample disc puts the necessary class information directly into the registry. If you define your own device class as part of a production driver package, however, you will need this section. Note also that Microsoft discourages installing a new class without using an INF.

A Property Page Provider

Way back in Chapter 1, "Introduction"—in Figure 1-6, to be precise—I showed you a screen shot of the property page I invented for use with the Sample device class. The SAMCLASS sample on the companion disc is the source code for the property page provider that produced that page, and I'm now going to explain how it works.

A property page provider for a device class is a 32-bit DLL with the following contents:

  • An exported entry point for each class for which the DLL supplies property pages
  • Dialog resources for each property page
  • A dialog procedure for each property page

In general, a single DLL can provide property pages for several device classes. Microsoft supplies some DLLs with the operating system that do this, for example. SAMCLASS, however, provides only a single page for a single class of device. Its only exported entry point is the following function:

extern "C" BOOL CALLBACK EnumPropPages (PSP_PROPSHEETPAGE_REQUEST p, LPFNADDPROPSHEETPAGE AddPage, LPARAM lParam) { PROPSHEETPAGE page; HPROPSHEETPAGE hpage; memset(&page, 0, sizeof(page)); page.dwSize = sizeof(PROPSHEETPAGE); page.hInstance = hInst; page.pszTemplate = MAKEINTRESOURCE(IDD_SAMPAGE); page.pfnDlgProc = PageDlgProc; <some more stuff> hpage = CreatePropertySheetPage(&page); if (!hpage) return TRUE; if (!(*AddPage)(hpage, lParam)) DestroyPropertySheetPage(hpage); return TRUE; }

When the Device Manager is about to construct the property sheet for a device, it consults the class registry key to see if there's a property page provider. You can designate a provider with a line like the following in your INF file:

[SamclassAddReg] HKR,,EnumPropPages32,,"samclass.dll,EnumPropPages"

The Device Manager loads the DLL you specify (SAMCLASS.DLL) and calls the designated entry point (EnumPropPages). If the function returns TRUE, the Device Manager will display the property page; otherwise, it won't. The function can add zero or more pages by calling the AddPage function as shown in the preceding example.

Inside the SP_PROPSHEETPAGE_REQUEST structure your enumeration function receives as an argument, you'll find two very useful pieces of information: a handle to a device information set, and the address of an SP_DEVINFO_DATA structure that pertains to the device you're concerned with. These data items (but not, unfortunately, the SP_PROPSHEETPAGE_REQUEST structure that contains them) remain valid for as long as the property page is visible, and it would be useful for you to be able to access them inside the dialog procedure you write for your property page. Windows SDK Programming 101 (well, maybe 102, because this is a little obscure) taught you how to do this. First create an auxiliary structure whose address you pass to CreatePropertySheetPage as the lParam member of the PROPSHEETPAGE structure:

struct SETUPSTUFF { HDEVINFO info; PSP_DEVINFO_DATA did; }; BOOL EnumPropPages(...) { PROPSHEETPAGE page; ... SETUPSTUFF* stuff = new SETUPSTUFF; stuff->info = p->DeviceInfoSet; stuff->did = p->DeviceInfoData; page.lParam = (LPARAM) stuff; page.pfnCallback = PageCallbackProc; page.dwFlags = PSP_USECALLBACK; ... } UINT CALLBACK PageCallbackProc(HWND junk, UINT msg, LPPROPSHEETPAGE p) { if (msg == PSPCB_RELEASE && p->lParam) delete (SETUPSTUFF*) p->lParam; return TRUE; }

The WM_INITDIALOG message that Windows sends to your dialog procedure gets an lParam value that's a pointer to the same PROPSHEETPAGE structure, so you can retrieve the stuff pointer there. You can then use SetWindowLong and GetWindowLong to save any desired information in the DWL_USER slot associated with the dialog object. In SAMCLASS, I chose to determine the name of a readme file that would describe the sample driver. I'll show you the code for doing that in a couple of paragraphs.

You also need to provide a way to delete the SETUPSTUFF structure when it's no longer needed. The easiest way, which works whether or not you ever get a WM_INITDIALOG message—you won't if there's an error constructing your property page—is to use a property page callback function as shown in the preceding fragment.

You can do all sorts of things in a custom property page. For the sample class, I wanted to provide a button that would bring up an explanation for each sample device. To keep things as general as possible, I decided to put a SampleInfo value naming the explanation file in the device's hardware registry key. To invoke a viewer for the explanation file, it suffices to call ShellExecute, which will interpret the file extension and locate an appropriate viewer application. For my book samples, the explanation files are HTML files, so the viewer in question will be your Web browser.

Most of the work in SAMCLASS occurs in the WM_INITDIALOG handler. (Error checking is again omitted.)

 1  2  3  4  
case WM_INITDIALOG: { SETUPSTUFF* stuff = (SETUPSTUFF*) ((LPPROPSHEETPAGE) lParam)->lParam; BOOL okay = FALSE; TCHAR name[256]; SetupDiGetDeviceRegistryProperty(stuff->info, stuff->did, SPDRP_FRIENDLYNAME, NULL, (PBYTE) name, sizeof(name), NULL); SetDlgItemText(hdlg, IDC_SAMNAME, name); HKEY hkey = SetupDiOpenDevRegKey(stuff->info, stuff->did, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); DWORD length = sizeof(name); RegQueryValueEx(hkey, "SampleInfo", NULL, NULL, (LPBYTE) name, &length); LPSTR infofile; DoEnvironmentSubst(name, sizeof(name)); infofile = (LPSTR) GlobalAlloc(GMEM_FIXED, strlen(name)+1); strcpy(infofile, name); SetWindowLong(hdlg, DWL_USER, (LONG) infofile); RegCloseKey(hkey); break; }

  1. Here, we determine the FriendlyName for the device and put it into a static text control. The actual code sample receives the device description if there's no friendly name.
  2. The next few statements determine the SampleInfo filename from the hardware key's parameter subkey.
  3. The strings I put in the registry are of the form %wdmbook%\chap12\devprop\devprop.htm, in which %wdmbook% indicates substitution by the value of the WDMBOOK environment variable. The call to DoEnvironmentSubst, a standard Win32 API, expands the environment variable.
  4. I need to remember the name of the SampleInfo file somewhere, and SetWindowLong provides a convenient way to do that.

When the end user—that would be you in this particular situation, I think—presses the More Information button on the property page, the dialog procedure receives a WM_COMMAND message, which it processes as shown below.

case WM_COMMAND: switch (LOWORD(wParam)) { case IDB_MOREINFO: { LPSTR infofile = (LPSTR) GetWindowLong(hdlg, DWL_USER); ShellExecute(hdlg, NULL, infofile, NULL, NULL, SW_SHOWNORMAL); return TRUE; } } break;

ShellExecute will launch the application associated with the SampleInfo file—namely, your Web browser—whereupon you can view the file and find all sorts of interesting information.

Other Class-Specific Information

In the preceding section, I showed you how an EnumPropPages32 registry entry controls the display of property pages for devices belonging to your custom class. Here are some other registry entries that you can use to tailor features of the class:

  • Installer32 designates a DLL that performs installation functions for devices belonging to the class. Writing a class installer is a huge undertaking, not least because the DDK documentation hasn't caught up to the software in this area. I didn't attempt to write a class installer for the Sample class.
  • Class is the class name as it should be spelled in INF file Class= statements.
  • Icon designates an icon to use in user interface displays about the class. This value is a string containing a decimal integer. A positive value designates an icon in the Installer32 DLL; documentation says that the system will find the icon in your EnumPropPages32 DLL if you don't have a class installer, but I didn't find that to be the case. A negative number designates an icon (whose index is the absolute value) in SETUPAPI.DLL. If you don't specify an icon, the system uses a nondescript gray diamond. I decided to use the value -5 for the Sample class, which designates an icon that looks vaguely like a PCI card. In fact, the system uses the same icon for network cards, but I liked this choice better than the others.
  • NoInstallClass, if present and not equal to 0, indicates that some enumerator will automatically detect any device belonging to this class. If the class has this attribute, the hardware wizard won't include this class in the list of device classes it presents to the end user.
  • SilentInstall, if present and not equal to 0, causes the PnP manager to install devices of this class without presenting any dialogs to the end user.
  • UpperFilters and LowerFilters specify service names for filter drivers. The PnP Manager loads these filters for every device belonging to the class. (You specify filter drivers that apply to just one device in the device's hardware key.)
  • NoDisplayClass, if present and not equal to 0, suppresses devices of this class from the Device Manager display.

A class key may also specify DeviceCharacteristics, DeviceType, and/or Security properties that contain overriding values for certain device attributes. I discussed these values in Chapter 2, "Basic Structure of a WDM Driver," in the section "The Role of the Registry." The PnP Manager applies these overrides when it creates a physical device object (PDO). I'm guessing here, but I suspect that someday a system administrator will somehow be able to examine and change these properties.



Programming the Microsoft Windows Driver Model
Programming the Microsoft Windows Driver Model
ISBN: 0735618038
EAN: 2147483647
Year: 1999
Pages: 93
Authors: Walter Oney

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net